mirror of
https://github.com/AssetRipper/AssetRipper.Primitives.git
synced 2026-11-13 04:26:30 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e8940973f | ||
|
|
64f50b46fb | ||
|
|
fbdda777ac | ||
|
|
2de06bfaf4 | ||
|
|
c7a8932863 | ||
|
|
4bcc823371 | ||
|
|
7630da6da0 | ||
|
|
e5802e39ee | ||
|
|
c663c68124 | ||
|
|
fa2458cfae | ||
|
|
ee923d8e9b | ||
|
|
8b23a0c671 | ||
|
|
f56feaf217 | ||
|
|
bd575f0063 | ||
|
|
0a6b003bf2 | ||
|
|
f4026adfd0 | ||
|
|
8954b81f81 | ||
|
|
856d05dafe | ||
|
|
b88ae7c46f | ||
|
|
4c4289fddd | ||
|
|
379034a536 | ||
|
|
428756101a | ||
|
|
dc15723135 | ||
|
|
6452151c5c | ||
|
|
3bbd130e76 | ||
|
|
2ab6b413c4 | ||
|
|
29fc3f655c | ||
|
|
71efe9e898 | ||
|
|
c51c22a15c | ||
|
|
83d16e30d0 | ||
|
|
0fe68a61ba | ||
|
|
964baafad1 | ||
|
|
264694de87 | ||
|
|
406bc21ad8 | ||
|
|
f852851d24 | ||
|
|
d9b73345a6 | ||
|
|
167d4242b0 | ||
|
|
87a0f969a5 | ||
|
|
f499511551 | ||
|
|
94ad139e22 | ||
|
|
3b8d4eb470 | ||
|
|
a96a32e87e | ||
|
|
e9d121c927 | ||
|
|
eedce8a128 | ||
|
|
f67c61a3d5 | ||
|
|
878aa3d815 |
No files matched your search
@@ -7,14 +7,31 @@ on:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
net8:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/[email protected]
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --framework net8.0 --no-restore
|
||||
- name: Test
|
||||
run: dotnet test --framework net8.0 --no-build --verbosity normal
|
||||
|
||||
net7:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Restore dependencies
|
||||
@@ -29,9 +46,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
- name: Restore dependencies
|
||||
@@ -46,13 +63,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
uses: actions/setup-dotnet@v4.0.0
|
||||
with:
|
||||
dotnet-version: |
|
||||
5.0.x
|
||||
6.0.x
|
||||
dotnet-version: 5.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netframework4.8;net5.0;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netframework4.8;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.6.1">
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -68,8 +68,8 @@ public class ComparisonTests
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(new UnityVersion(2019, 1, 0, UnityVersionType.Final, 1).IsGreaterEqual(2019, 1, 0), Is.True);
|
||||
Assert.That(new UnityVersion(2019, 1, 0, UnityVersionType.Final, 1).IsLessEqual(2019, 1, 0), Is.True);
|
||||
Assert.That(new UnityVersion(2019, 1, 0, UnityVersionType.Final, 1).GreaterThanOrEquals(2019, 1, 0));
|
||||
Assert.That(new UnityVersion(2019, 1, 0, UnityVersionType.Final, 1).LessThanOrEquals(2019, 1, 0));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,28 @@ namespace AssetRipper.Primitives.Tests;
|
||||
public class ParsingTests
|
||||
{
|
||||
[TestCase("4.2.2f1", 4, 2, 2, UnityVersionType.Final, 1, null, "Normal Unity 4 Version")]
|
||||
[TestCase("4.2.2f1\n1", 4, 2, 2, UnityVersionType.Final, 1, 1, "Custom Unity 4 Version")]
|
||||
[TestCase("4.2.2f1\n1", 4, 2, 2, UnityVersionType.Final, 1, "\n1", "Custom Unity 4 Version")]
|
||||
[TestCase("2343.4.5f7", 2343, 4, 5, UnityVersionType.Final, 7, null, "Fictitious Future Version")]
|
||||
[TestCase("2019.2.2f1c2\n2", 2019, 2, 2, UnityVersionType.China, 2, 2, "Fake Custom Chinese Version")]
|
||||
[TestCase("2019.2.2f1c2\n2", 2019, 2, 2, UnityVersionType.China, 2, "\n2", "Fake Custom Chinese Version")]
|
||||
[TestCase("2019", 2019, 0, 0, UnityVersionType.Final, 1, null, "Major Only")]
|
||||
[TestCase("2019.4", 2019, 4, 0, UnityVersionType.Final, 1, null, "Major Minor Only")]
|
||||
[TestCase("2019.4.3", 2019, 4, 3, UnityVersionType.Final, 1, null, "Major Minor Build Only")]
|
||||
public void UnityVersionParsesCorrectly(string versionString, int major, int minor, int build, UnityVersionType type, int typeNumber, int? customEngine, string name)
|
||||
[TestCase("0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Only")]
|
||||
[TestCase("0.0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Minor Only")]
|
||||
[TestCase("0.0.0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Minor Build Only")]
|
||||
[TestCase("0.0.0b2", 0, 0, 0, UnityVersionType.Beta, 2, null, "Zero, Full")]
|
||||
[TestCase("2019.2.2f1-letters", 2019, 2, 2, UnityVersionType.Final, 1, "-letters", "Issue #40 - Appended Custom Characters")]
|
||||
public void UnityVersionParsesCorrectly(string versionString, int major, int minor, int build, UnityVersionType type, int typeNumber, string? customEngine, string name)
|
||||
{
|
||||
UnityVersion expected = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type, (byte)typeNumber);
|
||||
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out int? parsedCustomEngine);
|
||||
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out string? parsedCustomEngine);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(parsedCustomEngine, Is.EqualTo(customEngine), $"The custom engine boolean is incorrect for '{name}'");
|
||||
Assert.That(parsedVersion, Is.EqualTo(expected), $"The parsed version is incorrect for '{name}'");
|
||||
if (customEngine is not null || typeNumber is not 1)
|
||||
if (customEngine is not null || typeNumber is not 0 and not 1)
|
||||
{
|
||||
Assert.That(parsedVersion.ToString(UnityVersionFormatFlags.Default, parsedCustomEngine), Is.EqualTo(versionString));
|
||||
Assert.That(parsedVersion.ToString(UnityVersionFormatFlags.Default, parsedCustomEngine ?? ""), Is.EqualTo(versionString));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -30,7 +36,7 @@ public class ParsingTests
|
||||
public void UnityVersionToStringParsesCorrectly(UnityVersion version)
|
||||
{
|
||||
string versionString = version.ToString();
|
||||
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out int? customEngine);
|
||||
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out string? customEngine);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(customEngine, Is.Null);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class UnityGuidTests
|
||||
{
|
||||
Guid originalGuid = Guid.NewGuid();
|
||||
UnityGuid tobyteArrayGuid = new UnityGuid(originalGuid.ToByteArray());
|
||||
UnityGuid memoryMarshallGuid = new UnityGuid(MemoryMarshal.Cast<Guid, byte>(new ReadOnlySpan<Guid>(in originalGuid)));
|
||||
UnityGuid memoryMarshallGuid = Unsafe.As<Guid, UnityGuid>(ref originalGuid);
|
||||
Assert.That(memoryMarshallGuid, Is.EqualTo(tobyteArrayGuid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
namespace AssetRipper.Primitives.Tests;
|
||||
|
||||
public class Utf8StringTests
|
||||
{
|
||||
[Test]
|
||||
public void Utf8StringEqualityWorks()
|
||||
{
|
||||
Utf8String utf8Str = new Utf8String("AssetRipperTestString");
|
||||
Utf8String utf8Str2 = new Utf8String(utf8Str.Data.ToArray());
|
||||
|
||||
Assert.That(utf8Str2, Is.EqualTo(utf8Str));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringEmptyIsEquivalentToUtf8StringEmpty()
|
||||
{
|
||||
@@ -28,5 +37,51 @@ public class Utf8StringTests
|
||||
Utf8String systemString = "AssetRipperTestString";
|
||||
Assert.That(dataString, Is.EqualTo(systemString));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenationBetweenTwoUtf8StringsWorks()
|
||||
{
|
||||
Utf8String dataString = "AssetRipperTestString"u8;
|
||||
Utf8String systemString = "AssetRipperTestString";
|
||||
Utf8String concatenated = dataString + systemString;
|
||||
Assert.That(concatenated, Is.EqualTo((Utf8String)"AssetRipperTestStringAssetRipperTestString"u8));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenationBetweenThreeUtf8StringsWorksTheSameAsAddition()
|
||||
{
|
||||
Utf8String added = "String1"u8 + new Utf8String("2") + "3"u8;
|
||||
Utf8String concatenated = Utf8String.Concat("String1"u8, "2"u8, "3"u8);
|
||||
Assert.That(added, Is.EqualTo(concatenated));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenationBetweenFourUtf8StringsWorks()
|
||||
{
|
||||
Utf8String string1 = "hello"u8;
|
||||
Utf8String string2 = " world"u8;
|
||||
Utf8String string3 = "!"u8;
|
||||
Utf8String string4 = ", how are you?"u8;
|
||||
Utf8String concatenated = Utf8String.Concat(string1, string2, string3, string4);
|
||||
Assert.That(concatenated, Is.EqualTo((Utf8String)"hello world!, how are you?"u8));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNullOrEmptyReturnsTrueForEmptyString()
|
||||
{
|
||||
Assert.That(Utf8String.IsNullOrEmpty(Utf8String.Empty), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNullOrEmptyReturnsTrueForNullString()
|
||||
{
|
||||
Assert.That(Utf8String.IsNullOrEmpty(null), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsNullOrEmptyReturnsFalseForNonEmptyString()
|
||||
{
|
||||
Assert.That(Utf8String.IsNullOrEmpty("AssetRipperTestString"u8), Is.False);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netstandard2.0;net5.0;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netstandard2.0;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>ds5678</Authors>
|
||||
<Company>AssetRipper</Company>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Version>3.1.1</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<PackageId>AssetRipper.Primitives</PackageId>
|
||||
<PackageTags>C# assetripper unity unity3d</PackageTags>
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageProjectUrl>https://github.com/AssetRipper/AssetRipper.Primitives</PackageProjectUrl>
|
||||
<Copyright>Copyright (c) 2022-2023 ds5678</Copyright>
|
||||
<Copyright>Copyright (c) 2022-2024 ds5678</Copyright>
|
||||
<Description>Managed library for primitive types used in AssetRipper.</Description>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
@@ -25,15 +25,28 @@
|
||||
<IsTrimmable>true</IsTrimmable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="PolySharp" Version="1.13.2">
|
||||
<PackageReference Include="PolySharp" Version="1.14.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode">
|
||||
<Version>1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Memory">
|
||||
<Version>4.5.5</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,21 +1,28 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AssetRipper.Primitives;
|
||||
|
||||
[JsonConverter(typeof(UnityGuidJsonConverter))]
|
||||
#if NET5_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonConverter(typeof(UnityGuidJsonConverter))]
|
||||
#endif
|
||||
public readonly record struct UnityGuid
|
||||
{
|
||||
public UnityGuid(Guid guid)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
Span<byte> guidData = stackalloc byte[16];
|
||||
bool success = guid.TryWriteBytes(guidData);
|
||||
Debug.Assert(success);
|
||||
#else
|
||||
Span<byte> guidData = guid.ToByteArray();
|
||||
#endif
|
||||
ConvertSystemOrUnityBytes(guidData, guidData);
|
||||
Data0 = ReadUInt32LittleEndian(guidData, 0);
|
||||
Data1 = ReadUInt32LittleEndian(guidData, 1);
|
||||
@@ -44,10 +51,24 @@ public readonly record struct UnityGuid
|
||||
//This is not an acceptable way to convert between Unity and System Guids.
|
||||
//We only do it this way to efficiently get 16 random bytes.
|
||||
//We don't care about official Guid validity because Unity does not care either.
|
||||
Guid guid = Guid.NewGuid();
|
||||
ReadOnlySpan<Guid> guidSpan = new ReadOnlySpan<Guid>(in guid);
|
||||
ReadOnlySpan<byte> byteSpan = MemoryMarshal.AsBytes(guidSpan);
|
||||
return new UnityGuid(byteSpan);
|
||||
if (Unsafe.SizeOf<Guid>() == Unsafe.SizeOf<UnityGuid>())
|
||||
{
|
||||
Guid guid = Guid.NewGuid();
|
||||
return Unsafe.As<Guid, UnityGuid>(ref guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ThrowOrReturnDefault();
|
||||
}
|
||||
|
||||
static UnityGuid ThrowOrReturnDefault()
|
||||
{
|
||||
#if DEBUG
|
||||
throw new InvalidCastException($"{nameof(UnityGuid)} struct size does not match {nameof(Guid)}.");
|
||||
#else
|
||||
return default;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static explicit operator UnityGuid(Guid systemGuid) => new UnityGuid(systemGuid);
|
||||
@@ -57,7 +78,11 @@ public readonly record struct UnityGuid
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
unityGuid.Write(span);
|
||||
ConvertSystemOrUnityBytes(span, span);
|
||||
#if NET5_0_OR_GREATER
|
||||
return new Guid(span);
|
||||
#else
|
||||
return new Guid(span.ToArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
private void Write(Span<byte> span)
|
||||
@@ -77,7 +102,23 @@ public readonly record struct UnityGuid
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
Span<char> span = stackalloc char[32]
|
||||
Span<char> span = stackalloc char[32];
|
||||
ToString(span);
|
||||
return CreateString(span);
|
||||
|
||||
static string CreateString(Span<char> span)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
return new string(span);
|
||||
#else
|
||||
return new string(span.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void ToString(Span<char> buffer)
|
||||
{
|
||||
ReadOnlySpan<char> span = stackalloc char[32]
|
||||
{
|
||||
GetHexChar(Data0, 0),
|
||||
GetHexChar(Data0, 4),
|
||||
@@ -113,7 +154,7 @@ public readonly record struct UnityGuid
|
||||
GetHexChar(Data3, 28),
|
||||
};
|
||||
|
||||
return new string(span);
|
||||
span.CopyTo(buffer);
|
||||
|
||||
static char GetHexChar(uint value, int offset)
|
||||
{
|
||||
@@ -186,15 +227,31 @@ public readonly record struct UnityGuid
|
||||
/// <returns>A stable guid corresponding to the <paramref name="input"/>.</returns>
|
||||
public static UnityGuid Md5Hash(scoped ReadOnlySpan<byte> input)
|
||||
{
|
||||
byte[] hashBytes = MD5.HashData(input);
|
||||
ConvertSystemOrUnityBytes(hashBytes, hashBytes);
|
||||
return new UnityGuid(hashBytes);
|
||||
Span<byte> buffer = stackalloc byte[16];
|
||||
HashData(input, buffer);
|
||||
ConvertSystemOrUnityBytes(buffer, buffer);
|
||||
return new UnityGuid(buffer);
|
||||
}
|
||||
|
||||
private static void HashData(ReadOnlySpan<byte> data, Span<byte> buffer)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
MD5.HashData(data, buffer);
|
||||
#else
|
||||
MD5.Create().ComputeHash(data.ToArray()).AsSpan().CopyTo(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static UnityGuid Md5Hash(scoped ReadOnlySpan<byte> assemblyName, scoped ReadOnlySpan<byte> @namespace, scoped ReadOnlySpan<byte> className)
|
||||
{
|
||||
int length = assemblyName.Length + @namespace.Length + className.Length;
|
||||
Span<byte> input = length < 1024 ? stackalloc byte[length] : GC.AllocateUninitializedArray<byte>(length);
|
||||
Span<byte> input = length < 1024
|
||||
? stackalloc byte[length]
|
||||
#if NET5_0_OR_GREATER
|
||||
: GC.AllocateUninitializedArray<byte>(length);
|
||||
#else
|
||||
: new byte[length];
|
||||
#endif
|
||||
assemblyName.CopyTo(input);
|
||||
@namespace.CopyTo(input.Slice(assemblyName.Length));
|
||||
className.CopyTo(input.Slice(assemblyName.Length + @namespace.Length));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
@@ -6,41 +6,41 @@ public readonly partial struct UnityVersion
|
||||
private const ulong subMinorMask = 0x00000000FFFFFFFFUL;
|
||||
private const ulong subBuildMask = 0x000000000000FFFFUL;
|
||||
private const ulong subTypeMask = 0x00000000000000FFUL;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
public bool IsEqual(ushort major) => this == From(major);
|
||||
public bool IsEqual(ushort major, ushort minor) => this == From(major, minor);
|
||||
public bool IsEqual(ushort major, ushort minor, ushort build) => this == From(major, minor, build);
|
||||
public bool IsEqual(ushort major, ushort minor, ushort build, UnityVersionType type) => this == From(major, minor, build, type);
|
||||
public bool IsEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this == new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool IsEqual(string version) => this == Parse(version);
|
||||
|
||||
public bool IsLess(ushort major) => this < From(major);
|
||||
public bool IsLess(ushort major, ushort minor) => this < From(major, minor);
|
||||
public bool IsLess(ushort major, ushort minor, ushort build) => this < From(major, minor, build);
|
||||
public bool IsLess(ushort major, ushort minor, ushort build, UnityVersionType type) => this < From(major, minor, build, type);
|
||||
public bool IsLess(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this < new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool IsLess(string version) => this < Parse(version);
|
||||
public bool Equals(ushort major) => this == From(major);
|
||||
public bool Equals(ushort major, ushort minor) => this == From(major, minor);
|
||||
public bool Equals(ushort major, ushort minor, ushort build) => this == From(major, minor, build);
|
||||
public bool Equals(ushort major, ushort minor, ushort build, UnityVersionType type) => this == From(major, minor, build, type);
|
||||
public bool Equals(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this == new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool Equals(string version) => this == Parse(version);
|
||||
|
||||
public bool IsLessEqual(ushort major) => this <= From(major);
|
||||
public bool IsLessEqual(ushort major, ushort minor) => this <= From(major, minor);
|
||||
public bool IsLessEqual(ushort major, ushort minor, ushort build) => this <= From(major, minor, build);
|
||||
public bool IsLessEqual(ushort major, ushort minor, ushort build, UnityVersionType type) => this <= From(major, minor, build, type);
|
||||
public bool IsLessEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this <= new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool IsLessEqual(string version) => this <= Parse(version);
|
||||
public bool LessThan(ushort major) => this < From(major);
|
||||
public bool LessThan(ushort major, ushort minor) => this < From(major, minor);
|
||||
public bool LessThan(ushort major, ushort minor, ushort build) => this < From(major, minor, build);
|
||||
public bool LessThan(ushort major, ushort minor, ushort build, UnityVersionType type) => this < From(major, minor, build, type);
|
||||
public bool LessThan(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this < new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool LessThan(string version) => this < Parse(version);
|
||||
|
||||
public bool IsGreater(ushort major) => this > From(major);
|
||||
public bool IsGreater(ushort major, ushort minor) => this > From(major, minor);
|
||||
public bool IsGreater(ushort major, ushort minor, ushort build) => this > From(major, minor, build);
|
||||
public bool IsGreater(ushort major, ushort minor, ushort build, UnityVersionType type) => this > From(major, minor, build, type);
|
||||
public bool IsGreater(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this > new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool IsGreater(string version) => this > Parse(version);
|
||||
public bool LessThanOrEquals(ushort major) => this <= From(major);
|
||||
public bool LessThanOrEquals(ushort major, ushort minor) => this <= From(major, minor);
|
||||
public bool LessThanOrEquals(ushort major, ushort minor, ushort build) => this <= From(major, minor, build);
|
||||
public bool LessThanOrEquals(ushort major, ushort minor, ushort build, UnityVersionType type) => this <= From(major, minor, build, type);
|
||||
public bool LessThanOrEquals(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this <= new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool LessThanOrEquals(string version) => this <= Parse(version);
|
||||
|
||||
public bool IsGreaterEqual(ushort major) => this >= From(major);
|
||||
public bool IsGreaterEqual(ushort major, ushort minor) => this >= From(major, minor);
|
||||
public bool IsGreaterEqual(ushort major, ushort minor, ushort build) => this >= From(major, minor, build);
|
||||
public bool IsGreaterEqual(ushort major, ushort minor, ushort build, UnityVersionType type) => this >= From(major, minor, build, type);
|
||||
public bool IsGreaterEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this >= new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool IsGreaterEqual(string version) => this >= Parse(version);
|
||||
public bool GreaterThan(ushort major) => this > From(major);
|
||||
public bool GreaterThan(ushort major, ushort minor) => this > From(major, minor);
|
||||
public bool GreaterThan(ushort major, ushort minor, ushort build) => this > From(major, minor, build);
|
||||
public bool GreaterThan(ushort major, ushort minor, ushort build, UnityVersionType type) => this > From(major, minor, build, type);
|
||||
public bool GreaterThan(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this > new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool GreaterThan(string version) => this > Parse(version);
|
||||
|
||||
public bool GreaterThanOrEquals(ushort major) => this >= From(major);
|
||||
public bool GreaterThanOrEquals(ushort major, ushort minor) => this >= From(major, minor);
|
||||
public bool GreaterThanOrEquals(ushort major, ushort minor, ushort build) => this >= From(major, minor, build);
|
||||
public bool GreaterThanOrEquals(ushort major, ushort minor, ushort build, UnityVersionType type) => this >= From(major, minor, build, type);
|
||||
public bool GreaterThanOrEquals(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) => this >= new UnityVersion(major, minor, build, type, typeNumber);
|
||||
public bool GreaterThanOrEquals(string version) => this >= Parse(version);
|
||||
|
||||
private UnityVersion From(ushort major)
|
||||
{
|
||||
@@ -64,5 +64,4 @@ public readonly partial struct UnityVersion
|
||||
((ulong)(ushort)type << typeOffset) | subTypeMask & m_data;
|
||||
return new UnityVersion(data);
|
||||
}
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
}
|
||||
@@ -27,12 +27,7 @@ public readonly partial struct UnityVersion : IEquatable<UnityVersion>, ICompara
|
||||
/// </returns>
|
||||
public int CompareTo(UnityVersion other)
|
||||
{
|
||||
if (this > other)
|
||||
return 1;
|
||||
else if (this < other)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
return m_data.CompareTo(other.m_data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,6 +50,6 @@ public readonly partial struct UnityVersion : IEquatable<UnityVersion>, ICompara
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked(827 + 911 * m_data.GetHashCode());
|
||||
return m_data.GetHashCode();
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,11 @@ namespace AssetRipper.Primitives;
|
||||
|
||||
public readonly partial struct UnityVersion
|
||||
{
|
||||
private static readonly Regex majorRegex = new Regex(@"^([0-9]+)$", RegexOptions.Compiled);
|
||||
private static readonly Regex majorMinorRegex = new Regex(@"^([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
|
||||
private static readonly Regex majorMinorBuildRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
|
||||
private static readonly Regex normalRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)(\n[0-9]+)?$", RegexOptions.Compiled);
|
||||
private static readonly Regex chinaRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)(\n[0-9]+)?$", RegexOptions.Compiled);
|
||||
private static readonly Regex normalRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
|
||||
private static readonly Regex chinaRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the version as a string using <see cref="UnityVersionFormatFlags.Default"/>.
|
||||
@@ -34,17 +35,22 @@ public readonly partial struct UnityVersion
|
||||
/// Serialize the version as a string
|
||||
/// </summary>
|
||||
/// <param name="flags">The flags to control how the version is formatted</param>
|
||||
/// <param name="customEngineNumber">The custom engine number to be appended</param>
|
||||
/// <param name="customEngineString">The custom engine string to be appended</param>
|
||||
/// <returns>A new string containing the formatted version.</returns>
|
||||
public string ToString(UnityVersionFormatFlags flags, int? customEngineNumber)
|
||||
public string ToString(UnityVersionFormatFlags flags,
|
||||
#if !NET6_0_OR_GREATER
|
||||
string customEngineString = "")
|
||||
#else
|
||||
ReadOnlySpan<char> customEngineString = default)
|
||||
#endif
|
||||
{
|
||||
return customEngineNumber is null
|
||||
return customEngineString.Length == 0
|
||||
? ToString(flags)
|
||||
: (flags & UnityVersionFormatFlags.ExcludeType) != 0
|
||||
? ToStringWithoutType()
|
||||
: Type is not UnityVersionType.China || (flags & UnityVersionFormatFlags.UseShortChineseFormat) != 0
|
||||
? $"{Major}.{Minor}.{Build}{Type.ToCharacter()}{TypeNumber}\n{customEngineNumber}"
|
||||
: $"{Major}.{Minor}.{Build}f1c{TypeNumber}\n{customEngineNumber}";
|
||||
? $"{Major}.{Minor}.{Build}{Type.ToCharacter()}{TypeNumber}{customEngineString}"
|
||||
: $"{Major}.{Minor}.{Build}f1c{TypeNumber}{customEngineString}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,66 +65,98 @@ public readonly partial struct UnityVersion
|
||||
/// <summary>
|
||||
/// Parse a normal Unity version string
|
||||
/// </summary>
|
||||
/// <param name="version">A string to parse</param>
|
||||
/// <param name="s">A string to parse</param>
|
||||
/// <returns>The parsed Unity version</returns>
|
||||
/// <exception cref="ArgumentNullException">If the string is null or empty</exception>
|
||||
/// <exception cref="ArgumentException">If the string is in an invalid format</exception>
|
||||
public static UnityVersion Parse(string version) => Parse(version, out _);
|
||||
public static UnityVersion Parse(string s) => Parse(s, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Parse a normal Unity version string
|
||||
/// </summary>
|
||||
/// <param name="version">A string to parse</param>
|
||||
/// <param name="customEngine">True if this version was generated by a custom Unity Engine.</param>
|
||||
/// <param name="s">A string to parse</param>
|
||||
/// <param name="customEngine">Not null if this version was generated by a custom Unity Engine.</param>
|
||||
/// <returns>The parsed Unity version</returns>
|
||||
/// <exception cref="ArgumentNullException">If the string is null or empty</exception>
|
||||
/// <exception cref="ArgumentException">If the string is in an invalid format</exception>
|
||||
public static UnityVersion Parse(string version, out int? customEngine)
|
||||
public static UnityVersion Parse(string s, out string? customEngine)
|
||||
{
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(version));
|
||||
}
|
||||
return TryParse(s, out UnityVersion version, out customEngine)
|
||||
? version
|
||||
: throw new ArgumentException($"Invalid version format: {s}", nameof(s));
|
||||
}
|
||||
|
||||
if (normalRegex.TryMatch(version, out Match? match))
|
||||
/// <summary>
|
||||
/// Try to parse a normal Unity version string
|
||||
/// </summary>
|
||||
/// <param name="s">A string to parse</param>
|
||||
/// <param name="version">The parsed Unity version</param>
|
||||
/// <param name="customEngine">Not null if this version was generated by a custom Unity Engine.</param>
|
||||
/// <returns>True if parsing was successful</returns>
|
||||
public static bool TryParse(string s, out UnityVersion version, out string? customEngine)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
customEngine = null;
|
||||
version = default;
|
||||
return false;
|
||||
}
|
||||
else if (chinaRegex.TryMatch(s, out Match? match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
int build = int.Parse(match.Groups[3].Value);
|
||||
int typeNumber = int.Parse(match.Groups[4].Value);
|
||||
customEngine = GetNullableString(match.Groups[5]);
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.China, (byte)typeNumber);
|
||||
return true;
|
||||
}
|
||||
else if(normalRegex.TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
int build = int.Parse(match.Groups[3].Value);
|
||||
char type = match.Groups[4].Value[0];
|
||||
int typeNumber = int.Parse(match.Groups[5].Value);
|
||||
customEngine = ParseNullableInteger(match.Groups[6]);
|
||||
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type.ToUnityVersionType(), (byte)typeNumber);
|
||||
customEngine = GetNullableString(match.Groups[6]);
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type.ToUnityVersionType(), (byte)typeNumber);
|
||||
return true;
|
||||
}
|
||||
else if (majorMinorBuildRegex.TryMatch(version, out match))
|
||||
else if (majorMinorBuildRegex.TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
int build = int.Parse(match.Groups[3].Value);
|
||||
customEngine = null;
|
||||
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.Final, 1);
|
||||
version = major is not 0 || minor is not 0 || build is not 0
|
||||
? new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else if (majorMinorRegex.TryMatch(version, out match))
|
||||
else if (majorMinorRegex.TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
customEngine = null;
|
||||
return new UnityVersion((ushort)major, (ushort)minor, 0, UnityVersionType.Final, 1);
|
||||
version = major is not 0 || minor is not 0
|
||||
? new UnityVersion((ushort)major, (ushort)minor, 0, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else if (chinaRegex.TryMatch(version, out match))
|
||||
else if (majorRegex.TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
int build = int.Parse(match.Groups[3].Value);
|
||||
int typeNumber = int.Parse(match.Groups[4].Value);
|
||||
customEngine = ParseNullableInteger(match.Groups[5]);
|
||||
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.China, (byte)typeNumber);
|
||||
customEngine = null;
|
||||
version = major is not 0
|
||||
? new UnityVersion((ushort)major, 0, 0, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid version format: {version}", nameof(version));
|
||||
customEngine = null;
|
||||
version = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int? ParseNullableInteger(Capture capture) => capture.Length == 0 ? null : int.Parse(capture.Value);
|
||||
static string? GetNullableString(Capture capture) => capture.Length == 0 ? null : capture.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
@@ -27,9 +27,13 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
cachedString = "";
|
||||
}
|
||||
|
||||
public Utf8String(ReadOnlySpan<byte> data)
|
||||
public Utf8String(ReadOnlySpan<byte> data) : this(data.ToArray())
|
||||
{
|
||||
this.data = data.ToArray();
|
||||
}
|
||||
|
||||
private Utf8String(byte[] data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Utf8String(string @string)
|
||||
@@ -56,7 +60,14 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new();
|
||||
#if NET6_0_OR_GREATER
|
||||
hash.AddBytes(data);
|
||||
#else
|
||||
foreach (byte b in data)
|
||||
{
|
||||
hash.Add(b);
|
||||
}
|
||||
#endif
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
|
||||
@@ -79,7 +90,11 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
[return: NotNullIfNotNull(nameof(@string))]
|
||||
public static implicit operator Utf8String?(string? @string)
|
||||
{
|
||||
return @string is null ? null : new Utf8String(@string);
|
||||
return @string is null
|
||||
? null
|
||||
: @string.Length == 0
|
||||
? Empty
|
||||
: new Utf8String(@string);
|
||||
}
|
||||
|
||||
[return: NotNullIfNotNull(nameof(utf8String))]
|
||||
@@ -90,12 +105,207 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
|
||||
public static implicit operator Utf8String(ReadOnlySpan<byte> data)
|
||||
{
|
||||
return new Utf8String(data);
|
||||
return data.Length == 0 ? Empty : new Utf8String(data);
|
||||
}
|
||||
|
||||
public static implicit operator ReadOnlySpan<byte>(Utf8String? utf8String)
|
||||
{
|
||||
return utf8String is null ? default : utf8String.Data;
|
||||
}
|
||||
|
||||
public static Utf8String operator +(Utf8String? string1, Utf8String? string2)
|
||||
{
|
||||
return Concat(string1, string2);
|
||||
}
|
||||
|
||||
public static Utf8String operator +(Utf8String? string1, ReadOnlySpan<byte> string2)
|
||||
{
|
||||
return string1 is null
|
||||
? string2.Length == 0 ? Empty : new Utf8String(string2)
|
||||
: Concat(string1.Data, string2);
|
||||
}
|
||||
|
||||
public static Utf8String operator +(ReadOnlySpan<byte> string1, Utf8String? string2)
|
||||
{
|
||||
return string2 is null
|
||||
? string1.Length == 0 ? Empty : new Utf8String(string1)
|
||||
: Concat(string1, string2.Data);
|
||||
}
|
||||
|
||||
public static bool IsNullOrEmpty([NotNullWhen(false)] Utf8String? utf8String)
|
||||
{
|
||||
return utf8String is null || utf8String.IsEmpty;
|
||||
}
|
||||
|
||||
public static Utf8String Concat(Utf8String? string1, Utf8String? string2)
|
||||
{
|
||||
if (IsNullOrEmpty(string1))
|
||||
{
|
||||
return string2 ?? Empty;
|
||||
}
|
||||
if (IsNullOrEmpty(string2))
|
||||
{
|
||||
return string1;
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.data.Length + string2.data.Length];
|
||||
string1.data.CopyTo(data.AsSpan());
|
||||
string2.data.CopyTo(data.AsSpan(string1.data.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(Utf8String? string1, Utf8String? string2, Utf8String? string3)
|
||||
{
|
||||
if (IsNullOrEmpty(string1))
|
||||
{
|
||||
return Concat(string2, string3);
|
||||
}
|
||||
if (IsNullOrEmpty(string2))
|
||||
{
|
||||
return Concat(string1, string3);
|
||||
}
|
||||
if (IsNullOrEmpty(string3))
|
||||
{
|
||||
return Concat(string1, string2);
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.data.Length + string2.data.Length + string3.data.Length];
|
||||
string1.data.CopyTo(data.AsSpan());
|
||||
string2.data.CopyTo(data.AsSpan(string1.data.Length));
|
||||
string3.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(Utf8String? string1, Utf8String? string2, Utf8String? string3, Utf8String? string4)
|
||||
{
|
||||
if (IsNullOrEmpty(string1))
|
||||
{
|
||||
return Concat(string2, string3, string4);
|
||||
}
|
||||
if (IsNullOrEmpty(string2))
|
||||
{
|
||||
return Concat(string1, string3, string4);
|
||||
}
|
||||
if (IsNullOrEmpty(string3))
|
||||
{
|
||||
return Concat(string1, string2, string4);
|
||||
}
|
||||
if (IsNullOrEmpty(string4))
|
||||
{
|
||||
return Concat(string1, string2, string3);
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.data.Length + string2.data.Length + string3.data.Length + string4.data.Length];
|
||||
string1.data.CopyTo(data.AsSpan());
|
||||
string2.data.CopyTo(data.AsSpan(string1.data.Length));
|
||||
string3.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length));
|
||||
string4.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length + string3.data.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(params Utf8String?[] values)
|
||||
{
|
||||
if (values is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
}
|
||||
|
||||
int totalLength = 0;
|
||||
foreach (Utf8String? value in values)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
totalLength += value.data.Length;
|
||||
}
|
||||
|
||||
if (totalLength == 0)
|
||||
{
|
||||
return Empty;
|
||||
}
|
||||
|
||||
byte[] data = new byte[totalLength];
|
||||
int offset = 0;
|
||||
foreach (Utf8String? value in values)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
value.data.CopyTo(data.AsSpan(offset));
|
||||
offset += value.data.Length;
|
||||
}
|
||||
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2)
|
||||
{
|
||||
if (string1.Length == 0)
|
||||
{
|
||||
return string2.Length == 0 ? Empty : new Utf8String(string2);
|
||||
}
|
||||
if (string2.Length == 0)
|
||||
{
|
||||
return new Utf8String(string1);
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.Length + string2.Length];
|
||||
string1.CopyTo(data);
|
||||
string2.CopyTo(data.AsSpan(string1.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2, ReadOnlySpan<byte> string3)
|
||||
{
|
||||
if (string1.Length == 0)
|
||||
{
|
||||
return Concat(string2, string3);
|
||||
}
|
||||
if (string2.Length == 0)
|
||||
{
|
||||
return Concat(string1, string3);
|
||||
}
|
||||
if (string3.Length == 0)
|
||||
{
|
||||
return Concat(string1, string2);
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.Length + string2.Length + string3.Length];
|
||||
string1.CopyTo(data);
|
||||
string2.CopyTo(data.AsSpan(string1.Length));
|
||||
string3.CopyTo(data.AsSpan(string1.Length + string2.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
|
||||
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2, ReadOnlySpan<byte> string3, ReadOnlySpan<byte> string4)
|
||||
{
|
||||
if (string1.Length == 0)
|
||||
{
|
||||
return Concat(string2, string3, string4);
|
||||
}
|
||||
if (string2.Length == 0)
|
||||
{
|
||||
return Concat(string1, string3, string4);
|
||||
}
|
||||
if (string3.Length == 0)
|
||||
{
|
||||
return Concat(string1, string2, string4);
|
||||
}
|
||||
if (string4.Length == 0)
|
||||
{
|
||||
return Concat(string1, string2, string3);
|
||||
}
|
||||
|
||||
byte[] data = new byte[string1.Length + string2.Length + string3.Length + string4.Length];
|
||||
string1.CopyTo(data);
|
||||
string2.CopyTo(data.AsSpan(string1.Length));
|
||||
string3.CopyTo(data.AsSpan(string1.Length + string2.Length));
|
||||
string4.CopyTo(data.AsSpan(string1.Length + string2.Length + string3.Length));
|
||||
return new Utf8String(data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user