Update span extensions

This commit is contained in:
VaDiM
2026-02-21 03:20:05 +03:00
parent daf3e18bd6
commit ab5b81d01e
5 changed files with 174 additions and 122 deletions
+18 -19
View File
@@ -1,9 +1,9 @@
using System;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace AssetStudio
{
@@ -1463,7 +1463,6 @@ namespace AssetStudio
}
}
public static uint GetFormatSize(VertexFormat format)
{
switch (format)
@@ -1493,8 +1492,13 @@ namespace AssetStudio
return format >= VertexFormat.UInt8;
}
public static float[] BytesToFloatArray(byte[] inputBytes, VertexFormat format)
public static float[] BytesToFloatArray(ReadOnlySpan<byte> inputBytes, VertexFormat format)
{
if (format == VertexFormat.Float)
{
return MemoryMarshal.Cast<byte, float>(inputBytes).ToArray();
}
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new float[len];
@@ -1502,15 +1506,8 @@ namespace AssetStudio
{
switch (format)
{
case VertexFormat.Float:
#if NET
result[i] = BinaryPrimitives.ReadSingleLittleEndian(inputBytes.AsSpan(i * 4));
#else
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
#endif
break;
case VertexFormat.Float16:
result[i] = (float)HalfHelper.ToHalf(inputBytes, i * 2);
result[i] = (float)inputBytes.ReadHalf(i * 2);
break;
case VertexFormat.UNorm8:
result[i] = inputBytes[i] / 255f;
@@ -1519,10 +1516,10 @@ namespace AssetStudio
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
break;
case VertexFormat.UNorm16:
result[i] = BinaryPrimitives.ReadUInt16LittleEndian(inputBytes.AsSpan(i * 2)) / 65535f;
result[i] = inputBytes.ReadUInt16(i * 2) / 65535f;
break;
case VertexFormat.SNorm16:
result[i] = Math.Max(BinaryPrimitives.ReadInt16LittleEndian(inputBytes.AsSpan(i * 2)) / 32767f, -1f);
result[i] = Math.Max(inputBytes.ReadInt16(i * 2) / 32767f, -1f);
break;
}
}
@@ -1531,6 +1528,11 @@ namespace AssetStudio
public static int[] BytesToIntArray(ReadOnlySpan<byte> inputBytes, VertexFormat format)
{
if (format == VertexFormat.SInt32)
{
return MemoryMarshal.Cast<byte, int>(inputBytes).ToArray();
}
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new int[len];
@@ -1543,16 +1545,13 @@ namespace AssetStudio
result[i] = inputBytes[i];
break;
case VertexFormat.UInt16:
result[i] = BinaryPrimitives.ReadUInt16LittleEndian(inputBytes.Slice(i * 2));
result[i] = inputBytes.ReadUInt16(i * 2);
break;
case VertexFormat.SInt16:
result[i] = BinaryPrimitives.ReadInt16LittleEndian(inputBytes.Slice(i * 2));
result[i] = inputBytes.ReadInt16(i * 2);
break;
case VertexFormat.UInt32:
result[i] = (int)BinaryPrimitives.ReadUInt32LittleEndian(inputBytes.Slice(i * 4));
break;
case VertexFormat.SInt32:
result[i] = BinaryPrimitives.ReadInt32LittleEndian(inputBytes.Slice(i * 4));
result[i] = (int)inputBytes.ReadUInt32(i * 4);
break;
}
}
-95
View File
@@ -1,95 +0,0 @@
using System;
using System.Buffers.Binary;
using System.Text;
namespace AssetStudio
{
public static class EndianSpanReader
{
public static uint ReadUInt32(this Span<byte> data, int start, bool isBigEndian)
{
return ReadUInt32((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static uint ReadUInt32(this ReadOnlySpan<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadUInt32BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(start));
}
public static long ReadUInt16(this Span<byte> data, int start, bool isBigEndian)
{
return ReadUInt16((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static uint ReadUInt16(this ReadOnlySpan<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadUInt16BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(start));
}
public static long ReadInt64(this Span<byte> data, int start, bool isBigEndian)
{
return ReadInt64((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static long ReadInt64(this ReadOnlySpan<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadInt64BigEndian(data.Slice(start))
: BinaryPrimitives.ReadInt64LittleEndian(data.Slice(start));
}
public static float ReadSingle(this Span<byte> data, int start, bool isBigEndian)
{
return ReadSingle((ReadOnlySpan<byte>)data, start, isBigEndian);
}
#if NETFRAMEWORK
public static float ReadSingle(this ReadOnlySpan<byte> data, int start, bool isBigEndian)
{
var bytes = data.Slice(start, 4).ToArray();
if ((isBigEndian && BitConverter.IsLittleEndian) || (!isBigEndian && !BitConverter.IsLittleEndian))
bytes.AsSpan().Reverse();
return BitConverter.ToSingle(bytes, 0);
}
#else
public static float ReadSingle(this ReadOnlySpan<byte> data, int start, bool isBigEndian)
{
return isBigEndian
? BinaryPrimitives.ReadSingleBigEndian(data[start..])
: BinaryPrimitives.ReadSingleLittleEndian(data[start..]);
}
#endif
public static string ReadStringToNull(this Span<byte> data, int maxLength = 32767)
{
return ReadStringToNull((ReadOnlySpan<byte>)data, maxLength);
}
public static string ReadStringToNull(this ReadOnlySpan<byte> data, int maxLength = 32767)
{
Span<byte> bytes = stackalloc byte[maxLength];
var count = 0;
while (count != data.Length && count < maxLength)
{
var b = data[count];
if (b == 0)
{
break;
}
bytes[count] = b;
count++;
}
bytes = bytes.Slice(0, count);
#if NETFRAMEWORK
return Encoding.UTF8.GetString(bytes.ToArray());
#else
return Encoding.UTF8.GetString(bytes);
#endif
}
}
}
+148
View File
@@ -0,0 +1,148 @@
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Text;
namespace AssetStudio
{
public static class SpanExtensions
{
#if NETFRAMEWORK
private static readonly byte[] Buff = new byte[4];
#endif
public static ushort ReadUInt16(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadUInt16((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static ushort ReadUInt16(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadUInt16BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(start));
}
public static short ReadInt16(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadInt16((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static short ReadInt16(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadInt16BigEndian(data.Slice(start))
: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(start));
}
public static uint ReadUInt32(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadUInt32((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static uint ReadUInt32(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadUInt32BigEndian(data.Slice(start))
: BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(start));
}
public static int ReadInt32(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadInt32((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static int ReadInt32(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadInt32BigEndian(data.Slice(start))
: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(start));
}
public static long ReadInt64(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadInt64((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static long ReadInt64(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadInt64BigEndian(data.Slice(start))
: BinaryPrimitives.ReadInt64LittleEndian(data.Slice(start));
}
public static Half ReadHalf(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadHalf((ReadOnlySpan<byte>)data, start, isBigEndian);
}
public static float ReadSingle(this Span<byte> data, int start = 0, bool isBigEndian = false)
{
return ReadSingle((ReadOnlySpan<byte>)data, start, isBigEndian);
}
#if NETFRAMEWORK
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Half ReadHalf(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? throw new NotImplementedException()
: HalfHelper.ToHalf((ushort)BinaryPrimitives.ReadInt16LittleEndian(data.Slice(start)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float ReadSingle(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
data = data.Slice(start, 4);
if ((isBigEndian && BitConverter.IsLittleEndian) || (!isBigEndian && !BitConverter.IsLittleEndian))
(Buff[0], Buff[1], Buff[2], Buff[3]) = (data[3], data[2], data[1], data[0]);
else
(Buff[0], Buff[1], Buff[2], Buff[3]) = (data[0], data[1], data[2], data[3]);
return BitConverter.ToSingle(Buff, 0);
}
#else
public static Half ReadHalf(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadHalfBigEndian(data.Slice(start))
: BinaryPrimitives.ReadHalfLittleEndian(data.Slice(start));
}
public static float ReadSingle(this ReadOnlySpan<byte> data, int start = 0, bool isBigEndian = false)
{
return isBigEndian
? BinaryPrimitives.ReadSingleBigEndian(data[start..])
: BinaryPrimitives.ReadSingleLittleEndian(data[start..]);
}
#endif
public static string ReadStringToNull(this Span<byte> data, int start = 0, int maxLength = 32767)
{
return ReadStringToNull((ReadOnlySpan<byte>)data, start, maxLength);
}
public static string ReadStringToNull(this ReadOnlySpan<byte> data, int start = 0, int maxLength = 32767)
{
Span<byte> bytes = stackalloc byte[maxLength];
data = data.Slice(start);
var count = 0;
while (count != data.Length && count < maxLength)
{
var b = data[count];
if (b == 0)
{
break;
}
bytes[count] = b;
count++;
}
bytes = bytes.Slice(0, count);
#if NETFRAMEWORK
return Encoding.UTF8.GetString(bytes.ToArray());
#else
return Encoding.UTF8.GetString(bytes);
#endif
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ namespace AssetStudio
var dataLen = Read(headerBuff, 0, headerBuffLen);
Position = 0;
var signature = buff.ReadStringToNull(20);
var signature = buff.ReadStringToNull(maxLength: 20);
switch (signature)
{
case "UnityWeb":
+7 -7
View File
@@ -416,7 +416,7 @@ namespace AssetStudio
{
buff[i] = 0;
buff[i + 1] = 0;
buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i / 2) * 255f);
buff[i + 2] = (byte)MathF.Round((float)image_data.ReadHalf(i / 2) * 255f);
buff[i + 3] = 255;
}
return true;
@@ -427,8 +427,8 @@ namespace AssetStudio
for (var i = 0; i < outPutDataSize; i += 4)
{
buff[i] = 0;
buff[i + 1] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i + 2) * 255f);
buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i) * 255f);
buff[i + 1] = (byte)MathF.Round((float)image_data.ReadHalf(i + 2) * 255f);
buff[i + 2] = (byte)MathF.Round((float)image_data.ReadHalf(i) * 255f);
buff[i + 3] = 255;
}
return true;
@@ -438,10 +438,10 @@ namespace AssetStudio
{
for (var i = 0; i < outPutDataSize; i += 4)
{
buff[i] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 4) * 255f);
buff[i + 1] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 2) * 255f);
buff[i + 2] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2) * 255f);
buff[i + 3] = (byte)MathF.Round((float)HalfHelper.ToHalf(image_data, i * 2 + 6) * 255f);
buff[i] = (byte)MathF.Round((float)image_data.ReadHalf(i * 2 + 4) * 255f);
buff[i + 1] = (byte)MathF.Round((float)image_data.ReadHalf(i * 2 + 2) * 255f);
buff[i + 2] = (byte)MathF.Round((float)image_data.ReadHalf(i * 2) * 255f);
buff[i + 3] = (byte)MathF.Round((float)image_data.ReadHalf(i * 2 + 6) * 255f);
}
return true;
}