com.alicizax.unity.framework/Runtime/ABase/Extension/Extension/BufferExtension.cs

779 lines
25 KiB
C#
Raw Normal View History

2025-10-11 15:18:09 +08:00
using System;
using System.Buffers.Binary;
using System.Text;
public static class BufferExtension
{
/// <summary>
/// 整型的大小
/// </summary>
public const int IntSize = sizeof(int);
/// <summary>
/// 无符号整型的大小
/// </summary>
public const int UIntSize = sizeof(uint);
/// <summary>
/// 短整型的大小
/// </summary>
public const int ShortSize = sizeof(short);
/// <summary>
/// 无符号短整型的大小
/// </summary>
public const int UShortSize = sizeof(ushort);
/// <summary>
/// 长整型的大小
/// </summary>
public const int LongSize = sizeof(long);
/// <summary>
/// 单精度浮点数的大小
/// </summary>
public const int FloatSize = sizeof(float);
/// <summary>
/// 双精度浮点数的大小
/// </summary>
public const int DoubleSize = sizeof(double);
/// <summary>
/// 字节的大小
/// </summary>
public const int ByteSize = sizeof(byte);
/// <summary>
/// 有符号字节的大小
/// </summary>
public const int SbyteSize = sizeof(sbyte);
/// <summary>
/// 布尔值的大小
/// </summary>
public const int BoolSize = sizeof(bool);
#region Write
/// <summary>
/// 将整数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteInt(this byte[] buffer, int value, ref int offset)
{
if (offset + IntSize > buffer.Length)
{
offset += IntSize;
return;
}
fixed (byte* ptr = buffer)
{
*(int*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += IntSize;
}
}
/// <summary>
/// 将无符号整数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteUInt(this byte[] buffer, uint value, ref int offset)
{
if (offset + IntSize > buffer.Length)
{
offset += IntSize;
return;
}
var span = buffer.AsSpan<byte>();
ref var local = ref span;
int start = offset;
BinaryPrimitives.WriteUInt32BigEndian(local.Slice(start, local.Length - start), value);
offset += IntSize;
}
/// <summary>将一个16位无符号整数写入指定的缓冲区并更新偏移量。</summary>
/// <param name="buffer">要写入的缓冲区。</param>
/// <param name="value">要写入的值。</param>
/// <param name="offset">要写入值的缓冲区中的偏移量。</param>
public static void WriteUShort(this byte[] buffer, ushort value, ref int offset)
{
if (offset + 2 > buffer.Length)
{
offset += 2;
}
else
{
Span<byte> span = buffer.AsSpan<byte>();
ref Span<byte> local = ref span;
int start = offset;
BinaryPrimitives.WriteUInt16BigEndian(local.Slice(start, local.Length - start), value);
offset += 2;
}
}
/// <summary>
/// 将短整数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的短整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteShort(this byte[] buffer, short value, ref int offset)
{
if (offset + ShortSize > buffer.Length)
{
offset += ShortSize;
return;
}
fixed (byte* ptr = buffer)
{
*(short*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += ShortSize;
}
}
/// <summary>
/// 将长整数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的长整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteLong(this byte[] buffer, long value, ref int offset)
{
if (offset + LongSize > buffer.Length)
{
offset += LongSize;
return;
}
fixed (byte* ptr = buffer)
{
*(long*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += LongSize;
}
}
/// <summary>
/// 将单精度浮点数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的单精度浮点数值。</param>
/// <param name="offset">字节数组中的偏移量,传递引用以便更新偏移量。</param>
public static unsafe void WriteFloat(this byte[] buffer, float value, ref int offset)
{
if (offset + FloatSize > buffer.Length)
{
offset += FloatSize;
return;
}
fixed (byte* ptr = buffer)
{
*(float*)(ptr + offset) = value;
*(int*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(*(int*)(ptr + offset));
offset += FloatSize;
}
}
/// <summary>
/// 将双精度浮点数写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的双精度浮点数值。</param>
/// <param name="offset">字节数组中的偏移量,传递引用以便更新偏移量。</param>
public static unsafe void WriteDouble(this byte[] buffer, double value, ref int offset)
{
if (offset + DoubleSize > buffer.Length)
{
offset += DoubleSize;
return;
}
fixed (byte* ptr = buffer)
{
*(double*)(ptr + offset) = value;
*(long*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(*(long*)(ptr + offset));
offset += DoubleSize;
}
}
/// <summary>
/// 将字节写入字节数组中的指定偏移量处。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的字节值。</param>
/// <param name="offset">字节数组中的偏移量,传递引用以便更新偏移量。</param>
public static unsafe void WriteByte(this byte[] buffer, byte value, ref int offset)
{
if (offset + ByteSize > buffer.Length)
{
offset += ByteSize;
return;
}
fixed (byte* ptr = buffer)
{
*(ptr + offset) = value;
offset += ByteSize;
}
}
/// <summary>
/// 在给定的偏移量位置,向缓冲区中写入字节序列,不包含长度信息。
/// </summary>
/// <param name="buffer">目标缓冲区。</param>
/// <param name="value">要写入的字节数组。</param>
/// <param name="offset">偏移量。</param>
public static unsafe void WriteBytesWithoutLength(this byte[] buffer, byte[] value, ref int offset)
{
if (value == null)
{
buffer.WriteInt(0, ref offset);
return;
}
if (offset + value.Length + IntSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + value.Length + IntSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer, valPtr = value)
{
Buffer.MemoryCopy(valPtr, ptr + offset, value.Length, value.Length);
offset += value.Length;
}
}
/// <summary>
/// 将字节数组写入到缓冲区中,同时更新偏移量。
/// </summary>
/// <param name="buffer">目标缓冲区。</param>
/// <param name="value">要写入的字节数组。</param>
/// <param name="offset">偏移量。</param>
public static unsafe void WriteBytes(this byte[] buffer, byte[] value, ref int offset)
{
if (value == null)
{
buffer.WriteInt(0, ref offset);
return;
}
if (offset + value.Length + IntSize > buffer.Length)
{
offset += value.Length + IntSize;
return;
}
buffer.WriteInt(value.Length, ref offset);
System.Array.Copy(value, 0, buffer, offset, value.Length);
offset += value.Length;
}
/// <summary>
/// 将有符号字节写入到缓冲区中,同时更新偏移量。
/// </summary>
/// <param name="buffer">目标缓冲区。</param>
/// <param name="value">要写入的有符号字节。</param>
/// <param name="offset">偏移量。</param>
public static unsafe void WriteSByte(this byte[] buffer, sbyte value, ref int offset)
{
if (offset + SbyteSize > buffer.Length)
{
offset += SbyteSize;
return;
}
fixed (byte* ptr = buffer)
{
*(sbyte*)(ptr + offset) = value;
offset += SbyteSize;
}
}
/// <summary>
/// 将字符串写入到缓冲区中,同时更新偏移量。
/// </summary>
/// <param name="buffer">目标缓冲区。</param>
/// <param name="value">要写入的字符串。</param>
/// <param name="offset">偏移量。</param>
public static unsafe void WriteString(this byte[] buffer, string value, ref int offset)
{
if (value == null)
{
value = string.Empty;
}
int len = System.Text.Encoding.UTF8.GetByteCount(value);
if (len > short.MaxValue)
{
throw new ArgumentException($"字符串长度超过了 short.MaxValue {len}, {short.MaxValue}");
}
// 预判已经超出长度了,直接计算长度就行了
if (offset + len + ShortSize > buffer.Length)
{
offset += len + ShortSize;
return;
}
fixed (byte* ptr = buffer)
{
System.Text.Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, offset + ShortSize);
buffer.WriteShort((short)len, ref offset);
offset += len;
}
}
/// <summary>
/// 将布尔值写入到缓冲区中,同时更新偏移量。
/// </summary>
/// <param name="buffer">目标缓冲区。</param>
/// <param name="value">要写入的布尔值。</param>
/// <param name="offset">偏移量。</param>
public static unsafe void WriteBool(this byte[] buffer, bool value, ref int offset)
{
if (offset + BoolSize > buffer.Length)
{
offset += BoolSize;
return;
}
fixed (byte* ptr = buffer)
{
*(bool*)(ptr + offset) = value;
offset += BoolSize;
}
}
#endregion
#region Read
/// <summary>
/// 从字节数组中读取一个整数值。
/// </summary>
/// <param name="buffer">包含整数值的字节数组。</param>
/// <param name="offset">从字节数组中读取整数值的偏移量。</param>
/// <returns>从字节数组中读取的整数值。</returns>
public static unsafe int ReadInt(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + IntSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(int*)(ptr + offset);
offset += IntSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>
/// 从字节数组中读取一个无符号整数值。
/// </summary>
/// <param name="buffer">包含整数值的字节数组。</param>
/// <param name="offset">从字节数组中读取整数值的偏移量。</param>
/// <returns>从字节数组中读取的无符号整数值。</returns>
/// <exception cref="Exception"></exception>
public static uint ReadUInt(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + UIntSize)
{
throw new Exception("buffer read out of index");
}
Span<byte> span = buffer.AsSpan<byte>();
ref Span<byte> local = ref span;
int start = offset;
int num = (int)BinaryPrimitives.ReadUInt32BigEndian((ReadOnlySpan<byte>)local.Slice(start, local.Length - start));
offset += UIntSize;
return (uint)num;
}
/// <summary>
/// 从字节数组中读取一个短整数值。
/// </summary>
/// <param name="buffer">包含短整数值的字节数组。</param>
/// <param name="offset">从字节数组中读取短整数值的偏移量。</param>
/// <returns>从字节数组中读取的短整数值。</returns>
public static unsafe short ReadShort(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + ShortSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(short*)(ptr + offset);
offset += ShortSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>从字节数组中读取16位无符号整数并将偏移量向前移动。</summary>
/// <param name="buffer">要读取的字节数组。</param>
/// <param name="offset">引用偏移量。</param>
/// <returns>返回读取的16位无符号整数。</returns>
public static ushort ReadUShort(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + UShortSize)
{
throw new Exception("buffer read out of index");
}
Span<byte> span = buffer.AsSpan<byte>();
ref Span<byte> local = ref span;
int start = offset;
int num = (int)BinaryPrimitives.ReadUInt16BigEndian((ReadOnlySpan<byte>)local.Slice(start, local.Length - start));
offset += UShortSize;
return (ushort)num;
}
/// <summary>
/// 从字节数组中读取一个长整型数值。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>长整型数值。</returns>
public static unsafe long ReadLong(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + LongSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(long*)(ptr + offset);
offset += LongSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>
/// 从字节数组中读取一个单精度浮点数值。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>单精度浮点数值。</returns>
public static unsafe float ReadFloat(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + FloatSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
*(int*)(ptr + offset) = System.Net.IPAddress.NetworkToHostOrder(*(int*)(ptr + offset));
var value = *(float*)(ptr + offset);
offset += FloatSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取一个双精度浮点数值。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>双精度浮点数值。</returns>
public static unsafe double ReadDouble(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + DoubleSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
*(long*)(ptr + offset) = System.Net.IPAddress.NetworkToHostOrder(*(long*)(ptr + offset));
var value = *(double*)(ptr + offset);
offset += DoubleSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取一个字节。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>字节值。</returns>
public static unsafe byte ReadByte(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + ByteSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(ptr + offset);
offset += ByteSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取一定长度的字节。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <param name="len">数据长度。</param>
/// <returns>读取的字节数组。</returns>
public static unsafe byte[] ReadBytes(this byte[] buffer, int offset, int len)
{
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
{
return Array.Empty<byte>();
}
var data = new byte[len];
System.Array.Copy(buffer, offset, data, 0, len);
return data;
}
/// <summary>
/// 从字节数组中读取一定长度的字节。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <param name="len">数据长度。</param>
/// <returns>读取的字节数组。</returns>
public static unsafe byte[] ReadBytes(this byte[] buffer, ref int offset, int len)
{
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
{
return Array.Empty<byte>();
}
var data = new byte[len];
System.Array.Copy(buffer, offset, data, 0, len);
offset += len;
return data;
}
/// <summary>
/// 从字节数组中读取一定长度的字节。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>读取的字节数组。</returns>
public static unsafe byte[] ReadBytes(this byte[] buffer, ref int offset)
{
var len = ReadInt(buffer, ref offset);
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
{
return Array.Empty<byte>();
}
var data = new byte[len];
System.Array.Copy(buffer, offset, data, 0, len);
offset += len;
return data;
}
/// <summary>
/// 从字节数组中读取有符号字节。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>读取的有符号字节。</returns>
public static unsafe sbyte ReadSByte(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + ByteSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(sbyte*)(ptr + offset);
offset += ByteSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取字符串。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>读取的字符串。</returns>
public static unsafe string ReadString(this byte[] buffer, ref int offset)
{
fixed (byte* ptr = buffer)
{
var len = ReadShort(buffer, ref offset);
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
return "";
var value = System.Text.Encoding.UTF8.GetString(buffer, offset, len);
offset += len;
return value;
}
}
/// <summary>
/// 从字节数组中读取布尔值。
/// </summary>
/// <param name="buffer">字节数组。</param>
/// <param name="offset">偏移量。</param>
/// <returns>读取的布尔值。</returns>
public static unsafe bool ReadBool(this byte[] buffer, ref int offset)
{
if (offset > buffer.Length + BoolSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(bool*)(ptr + offset);
offset += BoolSize;
return value;
}
}
#endregion
/// <summary>
/// 将字节数组转换为字符串
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string ToArrayString(this byte[] bytes)
{
StringBuilder.Clear();
foreach (byte b in bytes)
{
StringBuilder.Append(b + " ");
}
return StringBuilder.ToString();
}
private static readonly StringBuilder StringBuilder = new StringBuilder();
/// <summary>
/// 将字节转换为十六进制字符串。
/// </summary>
/// <param name="b">要转换的字节。</param>
/// <returns>表示字节的十六进制字符串。</returns>
public static string ToHex(this byte b)
{
return b.ToString("X2");
}
/// <summary>
/// 将字节数组转换为十六进制字符串。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <returns>表示字节数组的十六进制字符串。</returns>
public static string ToHex(this byte[] bytes)
{
StringBuilder.Clear();
foreach (byte b in bytes)
{
StringBuilder.Append(b.ToString("X2"));
}
return StringBuilder.ToString();
}
/// <summary>
/// 使用指定格式将字节数组转换为十六进制字符串。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <param name="format">十六进制格式。</param>
/// <returns>表示字节数组的十六进制字符串。</returns>
public static string ToHex(this byte[] bytes, string format)
{
StringBuilder.Clear();
foreach (byte b in bytes)
{
StringBuilder.Append(b.ToString(format));
}
return StringBuilder.ToString();
}
/// <summary>
/// 将字节数组中指定范围的字节转换为十六进制字符串。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <param name="offset">起始偏移量。</param>
/// <param name="count">要转换的字节数。</param>
/// <returns>表示指定范围内字节的十六进制字符串。</returns>
public static string ToHex(this byte[] bytes, int offset, int count)
{
StringBuilder.Clear();
for (int i = offset; i < offset + count; ++i)
{
StringBuilder.Append(bytes[i].ToString("X2"));
}
return StringBuilder.ToString();
}
/// <summary>
/// 将字节数组转换为字符串,使用默认编码。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <returns>转换后的字符串。</returns>
public static string ToDefaultString(this byte[] bytes)
{
return Encoding.Default.GetString(bytes);
}
/// <summary>
/// 将字节数组的一部分转换为字符串,使用默认编码。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <param name="index">起始位置。</param>
/// <param name="count">要转换的字节数。</param>
/// <returns>转换后的字符串。</returns>
public static string ToDefaultString(this byte[] bytes, int index, int count)
{
return Encoding.Default.GetString(bytes, index, count);
}
/// <summary>
/// 将字节数组转换为字符串使用UTF-8编码。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <returns>转换后的字符串。</returns>
public static string ToUtf8String(this byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
/// <summary>
/// 将字节数组的一部分转换为字符串使用UTF-8编码。
/// </summary>
/// <param name="bytes">要转换的字节数组。</param>
/// <param name="index">起始位置。</param>
/// <param name="count">要转换的字节数。</param>
/// <returns>转换后的字符串。</returns>
public static string ToUtf8String(this byte[] bytes, int index, int count)
{
return Encoding.UTF8.GetString(bytes, index, count);
}
}