com.alicizax.unity.framework/Runtime/ABase/Extension/Extension/BufferExtension.cs
2025-10-11 15:18:09 +08:00

779 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}