1569 lines
45 KiB
C#
1569 lines
45 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Numerics;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
|
|
namespace Bright.Serialization
|
|
{
|
|
|
|
public enum EDeserializeError
|
|
{
|
|
OK,
|
|
NOT_ENOUGH,
|
|
EXCEED_SIZE,
|
|
// UNMARSHAL_ERR,
|
|
}
|
|
|
|
public class SerializationException : Exception
|
|
{
|
|
public SerializationException() { }
|
|
public SerializationException(string msg) : base(msg) { }
|
|
|
|
public SerializationException(string message, Exception innerException) : base(message, innerException)
|
|
{
|
|
}
|
|
}
|
|
|
|
public readonly struct SegmentSaveState
|
|
{
|
|
public SegmentSaveState(int readerIndex, int writerIndex)
|
|
{
|
|
ReaderIndex = readerIndex;
|
|
WriterIndex = writerIndex;
|
|
}
|
|
|
|
public int ReaderIndex { get; }
|
|
|
|
public int WriterIndex { get; }
|
|
}
|
|
|
|
public sealed class ByteBuf : ICloneable, IEquatable<ByteBuf>
|
|
{
|
|
public ByteBuf()
|
|
{
|
|
Bytes = Array.Empty<byte>();
|
|
ReaderIndex = WriterIndex = 0;
|
|
}
|
|
|
|
public ByteBuf(int capacity)
|
|
{
|
|
Bytes = capacity > 0 ? new byte[capacity] : Array.Empty<byte>();
|
|
ReaderIndex = 0;
|
|
WriterIndex = 0;
|
|
}
|
|
|
|
public ByteBuf(byte[] bytes)
|
|
{
|
|
Bytes = bytes;
|
|
ReaderIndex = 0;
|
|
WriterIndex = Capacity;
|
|
}
|
|
|
|
public ByteBuf(byte[] bytes, int readIndex, int writeIndex)
|
|
{
|
|
Bytes = bytes;
|
|
ReaderIndex = readIndex;
|
|
WriterIndex = writeIndex;
|
|
}
|
|
|
|
public ByteBuf(int capacity, Action<ByteBuf> releaser) : this(capacity)
|
|
{
|
|
_releaser = releaser;
|
|
}
|
|
|
|
public static ByteBuf Wrap(byte[] bytes)
|
|
{
|
|
return new ByteBuf(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
public void Replace(byte[] bytes)
|
|
{
|
|
Bytes = bytes;
|
|
ReaderIndex = 0;
|
|
WriterIndex = Capacity;
|
|
}
|
|
|
|
public void Replace(byte[] bytes, int beginPos, int endPos)
|
|
{
|
|
Bytes = bytes;
|
|
ReaderIndex = beginPos;
|
|
WriterIndex = endPos;
|
|
}
|
|
|
|
public int ReaderIndex { get; set; }
|
|
|
|
public int WriterIndex { get; set; }
|
|
|
|
private readonly Action<ByteBuf> _releaser;
|
|
|
|
public int Capacity => Bytes.Length;
|
|
|
|
public int Size { get { return WriterIndex - ReaderIndex; } }
|
|
|
|
public bool Empty => WriterIndex <= ReaderIndex;
|
|
|
|
public bool NotEmpty => WriterIndex > ReaderIndex;
|
|
|
|
|
|
public void AddWriteIndex(int add)
|
|
{
|
|
WriterIndex += add;
|
|
}
|
|
|
|
public void AddReadIndex(int add)
|
|
{
|
|
ReaderIndex += add;
|
|
}
|
|
|
|
#pragma warning disable CA1819 // 属性不应返回数组
|
|
public byte[] Bytes { get; private set; }
|
|
#pragma warning restore CA1819 // 属性不应返回数组
|
|
|
|
public byte[] CopyData()
|
|
{
|
|
var n = Remaining;
|
|
if (n > 0)
|
|
{
|
|
var arr = new byte[n];
|
|
Buffer.BlockCopy(Bytes, ReaderIndex, arr, 0, n);
|
|
return arr;
|
|
}
|
|
else
|
|
{
|
|
return Array.Empty<byte>();
|
|
}
|
|
}
|
|
|
|
public int Remaining { get { return WriterIndex - ReaderIndex; } }
|
|
|
|
public void DiscardReadBytes()
|
|
{
|
|
WriterIndex -= ReaderIndex;
|
|
Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex);
|
|
ReaderIndex = 0;
|
|
}
|
|
|
|
public int NotCompactWritable { get { return Capacity - WriterIndex; } }
|
|
|
|
public void WriteBytesWithoutSize(byte[] bs)
|
|
{
|
|
WriteBytesWithoutSize(bs, 0, bs.Length);
|
|
}
|
|
|
|
public void WriteBytesWithoutSize(byte[] bs, int offset, int len)
|
|
{
|
|
EnsureWrite(len);
|
|
Buffer.BlockCopy(bs, offset, Bytes, WriterIndex, len);
|
|
WriterIndex += len;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
ReaderIndex = WriterIndex = 0;
|
|
}
|
|
|
|
private const int MIN_CAPACITY = 16;
|
|
|
|
private static int PropSize(int initSize, int needSize)
|
|
{
|
|
for (int i = Math.Max(initSize, MIN_CAPACITY); ; i <<= 1)
|
|
{
|
|
if (i >= needSize)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureWrite0(int size)
|
|
{
|
|
var needSize = WriterIndex + size - ReaderIndex;
|
|
if (needSize < Capacity)
|
|
{
|
|
WriterIndex -= ReaderIndex;
|
|
Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex);
|
|
ReaderIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
int newCapacity = PropSize(Capacity, needSize);
|
|
var newBytes = new byte[newCapacity];
|
|
WriterIndex -= ReaderIndex;
|
|
Buffer.BlockCopy(Bytes, ReaderIndex, newBytes, 0, WriterIndex);
|
|
ReaderIndex = 0;
|
|
Bytes = newBytes;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void EnsureWrite(int size)
|
|
{
|
|
if (WriterIndex + size > Capacity)
|
|
{
|
|
EnsureWrite0(size);
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private void EnsureRead(int size)
|
|
{
|
|
if (ReaderIndex + size > WriterIndex)
|
|
{
|
|
throw new SerializationException();
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private bool CanRead(int size)
|
|
{
|
|
return (ReaderIndex + size <= WriterIndex);
|
|
}
|
|
|
|
public void Append(byte x)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = x;
|
|
}
|
|
|
|
public void WriteBool(bool b)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = (byte)(b ? 1 : 0);
|
|
}
|
|
|
|
public bool ReadBool()
|
|
{
|
|
EnsureRead(1);
|
|
return Bytes[ReaderIndex++] != 0;
|
|
}
|
|
|
|
public void WriteByte(byte x)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = x;
|
|
}
|
|
|
|
public byte ReadByte()
|
|
{
|
|
EnsureRead(1);
|
|
return Bytes[ReaderIndex++];
|
|
}
|
|
|
|
|
|
public void WriteShort(short x)
|
|
{
|
|
if (x >= 0)
|
|
{
|
|
if (x < 0x80)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = (byte)x;
|
|
return;
|
|
}
|
|
else if (x < 0x4000)
|
|
{
|
|
EnsureWrite(2);
|
|
Bytes[WriterIndex + 1] = (byte)x;
|
|
Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
|
|
WriterIndex += 2;
|
|
return;
|
|
}
|
|
}
|
|
EnsureWrite(3);
|
|
Bytes[WriterIndex] = 0xff;
|
|
Bytes[WriterIndex + 2] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
WriterIndex += 3;
|
|
}
|
|
|
|
public short ReadShort()
|
|
{
|
|
EnsureRead(1);
|
|
int h = Bytes[ReaderIndex];
|
|
if (h < 0x80)
|
|
{
|
|
ReaderIndex++;
|
|
return (short)h;
|
|
}
|
|
else if (h < 0xc0)
|
|
{
|
|
EnsureRead(2);
|
|
int x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
|
|
ReaderIndex += 2;
|
|
return (short)x;
|
|
}
|
|
else if ((h == 0xff))
|
|
{
|
|
EnsureRead(3);
|
|
int x = (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
ReaderIndex += 3;
|
|
return (short)x;
|
|
}
|
|
else
|
|
{
|
|
throw new SerializationException();
|
|
}
|
|
}
|
|
|
|
public short ReadFshort()
|
|
{
|
|
EnsureRead(2);
|
|
short x;
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[ReaderIndex])
|
|
{
|
|
x = *(short*)b;
|
|
}
|
|
}
|
|
#else
|
|
x = (short)((Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex]);
|
|
|
|
#endif
|
|
ReaderIndex += 2;
|
|
return x;
|
|
}
|
|
|
|
public void WriteFshort(short x)
|
|
{
|
|
EnsureWrite(2);
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[WriterIndex])
|
|
{
|
|
*(short*)b = x;
|
|
}
|
|
}
|
|
#else
|
|
Bytes[WriterIndex] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
#endif
|
|
WriterIndex += 2;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void WriteInt(int x)
|
|
{
|
|
WriteUint((uint)x);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public int ReadInt()
|
|
{
|
|
return (int)ReadUint();
|
|
}
|
|
|
|
|
|
public void WriteUint(uint x)
|
|
{
|
|
// 如果有修改,记得也把 EndWriteSegment改了
|
|
// 0 111 1111
|
|
if (x < 0x80)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = (byte)x;
|
|
}
|
|
else if (x < 0x4000) // 10 11 1111, -
|
|
{
|
|
EnsureWrite(2);
|
|
Bytes[WriterIndex + 1] = (byte)x;
|
|
Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
|
|
WriterIndex += 2;
|
|
}
|
|
else if (x < 0x200000) // 110 1 1111, -,-
|
|
{
|
|
EnsureWrite(3);
|
|
Bytes[WriterIndex + 2] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0);
|
|
WriterIndex += 3;
|
|
}
|
|
else if (x < 0x10000000) // 1110 1111,-,-,-
|
|
{
|
|
EnsureWrite(4);
|
|
Bytes[WriterIndex + 3] = (byte)x;
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 16);
|
|
Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0);
|
|
WriterIndex += 4;
|
|
}
|
|
else
|
|
{
|
|
EnsureWrite(5);
|
|
Bytes[WriterIndex] = 0xf0;
|
|
Bytes[WriterIndex + 4] = (byte)x;
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 24);
|
|
WriterIndex += 5;
|
|
}
|
|
}
|
|
|
|
public uint ReadUint()
|
|
{
|
|
///
|
|
/// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets
|
|
EnsureRead(1);
|
|
uint h = Bytes[ReaderIndex];
|
|
if (h < 0x80)
|
|
{
|
|
ReaderIndex++;
|
|
return h;
|
|
}
|
|
else if (h < 0xc0)
|
|
{
|
|
EnsureRead(2);
|
|
uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
|
|
ReaderIndex += 2;
|
|
return x;
|
|
}
|
|
else if (h < 0xe0)
|
|
{
|
|
EnsureRead(3);
|
|
uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
ReaderIndex += 3;
|
|
return x;
|
|
}
|
|
else if (h < 0xf0)
|
|
{
|
|
|
|
EnsureRead(4);
|
|
uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
|
|
ReaderIndex += 4;
|
|
return x;
|
|
}
|
|
else
|
|
{
|
|
EnsureRead(5);
|
|
uint x = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4];
|
|
ReaderIndex += 5;
|
|
return x;
|
|
}
|
|
}
|
|
|
|
public unsafe void WriteUint_Unsafe(uint x)
|
|
{
|
|
// 0 111 1111
|
|
if (x < 0x80)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = (byte)(x << 1);
|
|
}
|
|
else if (x < 0x4000)// 10 11 1111, -
|
|
{
|
|
EnsureWrite(2);
|
|
|
|
fixed (byte* wb = &Bytes[WriterIndex])
|
|
{
|
|
*(uint*)(wb) = (x << 2 | 0b01);
|
|
}
|
|
|
|
WriterIndex += 2;
|
|
}
|
|
else if (x < 0x200000) // 110 1 1111, -,-
|
|
{
|
|
EnsureWrite(3);
|
|
|
|
fixed (byte* wb = &Bytes[WriterIndex])
|
|
{
|
|
*(uint*)(wb) = (x << 3 | 0b011);
|
|
}
|
|
WriterIndex += 3;
|
|
}
|
|
else if (x < 0x10000000) // 1110 1111,-,-,-
|
|
{
|
|
EnsureWrite(4);
|
|
fixed (byte* wb = &Bytes[WriterIndex])
|
|
{
|
|
*(uint*)(wb) = (x << 4 | 0b0111);
|
|
}
|
|
WriterIndex += 4;
|
|
}
|
|
else
|
|
{
|
|
EnsureWrite(5);
|
|
fixed (byte* wb = &Bytes[WriterIndex])
|
|
{
|
|
*(uint*)(wb) = (x << 5 | 0b01111);
|
|
}
|
|
WriterIndex += 5;
|
|
}
|
|
}
|
|
|
|
public unsafe uint ReadUint_Unsafe()
|
|
{
|
|
///
|
|
/// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets
|
|
EnsureRead(1);
|
|
uint h = Bytes[ReaderIndex];
|
|
if ((h & 0b1) == 0b0)
|
|
{
|
|
ReaderIndex++;
|
|
return (h >> 1);
|
|
}
|
|
else if ((h & 0b11) == 0b01)
|
|
{
|
|
EnsureRead(2);
|
|
fixed (byte* rb = &Bytes[ReaderIndex])
|
|
{
|
|
ReaderIndex += 2;
|
|
return (*(uint*)rb) >> 2;
|
|
}
|
|
}
|
|
else if ((h & 0b111) == 0b011)
|
|
{
|
|
EnsureRead(3);
|
|
fixed (byte* rb = &Bytes[ReaderIndex])
|
|
{
|
|
ReaderIndex += 3;
|
|
return (*(uint*)rb) >> 3;
|
|
}
|
|
}
|
|
else if ((h & 0b1111) == 0b0111)
|
|
{
|
|
EnsureRead(4);
|
|
fixed (byte* rb = &Bytes[ReaderIndex])
|
|
{
|
|
ReaderIndex += 4;
|
|
return (*(uint*)rb) >> 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EnsureRead(5);
|
|
fixed (byte* rb = &Bytes[ReaderIndex])
|
|
{
|
|
ReaderIndex += 5;
|
|
return (*(uint*)rb) >> 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
public int ReadFint()
|
|
{
|
|
EnsureRead(4);
|
|
int x;
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[ReaderIndex])
|
|
{
|
|
x = *(int*)b;
|
|
}
|
|
}
|
|
#else
|
|
x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
|
|
|
|
#endif
|
|
ReaderIndex += 4;
|
|
return x;
|
|
}
|
|
|
|
|
|
public void WriteFint(int x)
|
|
{
|
|
EnsureWrite(4);
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[WriterIndex])
|
|
{
|
|
*(int*)b = x;
|
|
}
|
|
}
|
|
#else
|
|
Bytes[WriterIndex] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 24);
|
|
#endif
|
|
WriterIndex += 4;
|
|
}
|
|
|
|
public int ReadFint_Safe()
|
|
{
|
|
EnsureRead(4);
|
|
int x;
|
|
|
|
x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
|
|
|
|
ReaderIndex += 4;
|
|
return x;
|
|
}
|
|
|
|
|
|
public void WriteFint_Safe(int x)
|
|
{
|
|
EnsureWrite(4);
|
|
Bytes[WriterIndex] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 24);
|
|
WriterIndex += 4;
|
|
}
|
|
|
|
public void WriteLong(long x)
|
|
{
|
|
WriteUlong((ulong)x);
|
|
}
|
|
|
|
public long ReadLong()
|
|
{
|
|
return (long)ReadUlong();
|
|
}
|
|
|
|
public void WriteNumberAsLong(double x)
|
|
{
|
|
WriteLong((long)x);
|
|
}
|
|
|
|
public double ReadLongAsNumber()
|
|
{
|
|
return ReadLong();
|
|
}
|
|
|
|
private void WriteUlong(ulong x)
|
|
{
|
|
// 0 111 1111
|
|
if (x < 0x80)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = (byte)x;
|
|
}
|
|
else if (x < 0x4000) // 10 11 1111, -
|
|
{
|
|
EnsureWrite(2);
|
|
Bytes[WriterIndex + 1] = (byte)x;
|
|
Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
|
|
WriterIndex += 2;
|
|
}
|
|
else if (x < 0x200000) // 110 1 1111, -,-
|
|
{
|
|
EnsureWrite(3);
|
|
Bytes[WriterIndex + 2] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0);
|
|
WriterIndex += 3;
|
|
}
|
|
else if (x < 0x10000000) // 1110 1111,-,-,-
|
|
{
|
|
EnsureWrite(4);
|
|
Bytes[WriterIndex + 3] = (byte)x;
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 16);
|
|
Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0);
|
|
WriterIndex += 4;
|
|
}
|
|
else if (x < 0x800000000L) // 1111 0xxx,-,-,-,-
|
|
{
|
|
EnsureWrite(5);
|
|
Bytes[WriterIndex + 4] = (byte)x;
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 24);
|
|
Bytes[WriterIndex] = (byte)((x >> 32) | 0xf0);
|
|
WriterIndex += 5;
|
|
}
|
|
else if (x < 0x40000000000L) // 1111 10xx,
|
|
{
|
|
EnsureWrite(6);
|
|
Bytes[WriterIndex + 5] = (byte)x;
|
|
Bytes[WriterIndex + 4] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 24);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 32);
|
|
Bytes[WriterIndex] = (byte)((x >> 40) | 0xf8);
|
|
WriterIndex += 6;
|
|
}
|
|
else if (x < 0x200000000000L) // 1111 110x,
|
|
{
|
|
EnsureWrite(7);
|
|
Bytes[WriterIndex + 6] = (byte)x;
|
|
Bytes[WriterIndex + 5] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 4] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 24);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 32);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 40);
|
|
Bytes[WriterIndex] = (byte)((x >> 48) | 0xfc);
|
|
WriterIndex += 7;
|
|
}
|
|
else if (x < 0x100000000000000L) // 1111 1110
|
|
{
|
|
EnsureWrite(8);
|
|
Bytes[WriterIndex + 7] = (byte)x;
|
|
Bytes[WriterIndex + 6] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 5] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 4] = (byte)(x >> 24);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 32);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 40);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 48);
|
|
Bytes[WriterIndex] = 0xfe;
|
|
WriterIndex += 8;
|
|
}
|
|
else // 1111 1111
|
|
{
|
|
EnsureWrite(9);
|
|
Bytes[WriterIndex] = 0xff;
|
|
Bytes[WriterIndex + 8] = (byte)x;
|
|
Bytes[WriterIndex + 7] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 6] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 5] = (byte)(x >> 24);
|
|
Bytes[WriterIndex + 4] = (byte)(x >> 32);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 40);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 48);
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 56);
|
|
WriterIndex += 9;
|
|
}
|
|
}
|
|
|
|
public ulong ReadUlong()
|
|
{
|
|
EnsureRead(1);
|
|
uint h = Bytes[ReaderIndex];
|
|
if (h < 0x80)
|
|
{
|
|
ReaderIndex++;
|
|
return h;
|
|
}
|
|
else if (h < 0xc0)
|
|
{
|
|
EnsureRead(2);
|
|
uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
|
|
ReaderIndex += 2;
|
|
return x;
|
|
}
|
|
else if (h < 0xe0)
|
|
{
|
|
EnsureRead(3);
|
|
uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
ReaderIndex += 3;
|
|
return x;
|
|
}
|
|
else if (h < 0xf0)
|
|
{
|
|
EnsureRead(4);
|
|
uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
|
|
ReaderIndex += 4;
|
|
return x;
|
|
}
|
|
else if (h < 0xf8)
|
|
{
|
|
EnsureRead(5);
|
|
uint xl = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | (Bytes[ReaderIndex + 4]);
|
|
uint xh = h & 0x07;
|
|
ReaderIndex += 5;
|
|
return ((ulong)xh << 32) | xl;
|
|
}
|
|
else if (h < 0xfc)
|
|
{
|
|
EnsureRead(6);
|
|
uint xl = ((uint)Bytes[ReaderIndex + 2] << 24) | ((uint)(Bytes[ReaderIndex + 3] << 16)) | ((uint)Bytes[ReaderIndex + 4] << 8) | (Bytes[ReaderIndex + 5]);
|
|
uint xh = ((h & 0x03) << 8) | Bytes[ReaderIndex + 1];
|
|
ReaderIndex += 6;
|
|
return ((ulong)xh << 32) | xl;
|
|
}
|
|
else if (h < 0xfe)
|
|
{
|
|
EnsureRead(7);
|
|
uint xl = ((uint)Bytes[ReaderIndex + 3] << 24) | ((uint)(Bytes[ReaderIndex + 4] << 16)) | ((uint)Bytes[ReaderIndex + 5] << 8) | (Bytes[ReaderIndex + 6]);
|
|
uint xh = ((h & 0x01) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
ReaderIndex += 7;
|
|
return ((ulong)xh << 32) | xl;
|
|
}
|
|
else if (h < 0xff)
|
|
{
|
|
EnsureRead(8);
|
|
uint xl = ((uint)Bytes[ReaderIndex + 4] << 24) | ((uint)(Bytes[ReaderIndex + 5] << 16)) | ((uint)Bytes[ReaderIndex + 6] << 8) | (Bytes[ReaderIndex + 7]);
|
|
uint xh = /*((h & 0x01) << 24) |*/ ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
|
|
ReaderIndex += 8;
|
|
return ((ulong)xh << 32) | xl;
|
|
}
|
|
else
|
|
{
|
|
EnsureRead(9);
|
|
uint xl = ((uint)Bytes[ReaderIndex + 5] << 24) | ((uint)(Bytes[ReaderIndex + 6] << 16)) | ((uint)Bytes[ReaderIndex + 7] << 8) | (Bytes[ReaderIndex + 8]);
|
|
uint xh = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)Bytes[ReaderIndex + 2] << 16) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4];
|
|
ReaderIndex += 9;
|
|
return ((ulong)xh << 32) | xl;
|
|
}
|
|
}
|
|
|
|
|
|
public void WriteFlong(long x)
|
|
{
|
|
EnsureWrite(8);
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[WriterIndex])
|
|
{
|
|
*(long*)b = x;
|
|
}
|
|
}
|
|
#else
|
|
|
|
Bytes[WriterIndex] = (byte)x;
|
|
Bytes[WriterIndex + 1] = (byte)(x >> 8);
|
|
Bytes[WriterIndex + 2] = (byte)(x >> 16);
|
|
Bytes[WriterIndex + 3] = (byte)(x >> 24);
|
|
Bytes[WriterIndex + 4] = (byte)(x >> 32);
|
|
Bytes[WriterIndex + 5] = (byte)(x >> 40);
|
|
Bytes[WriterIndex + 6] = (byte)(x >> 48);
|
|
Bytes[WriterIndex + 7] = (byte)(x >> 56);
|
|
#endif
|
|
WriterIndex += 8;
|
|
}
|
|
|
|
public long ReadFlong()
|
|
{
|
|
EnsureRead(8);
|
|
long x;
|
|
#if CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[ReaderIndex])
|
|
{
|
|
x = *(long*)b;
|
|
}
|
|
}
|
|
#else
|
|
int xl = (Bytes[ReaderIndex + 3] << 24) | ((Bytes[ReaderIndex + 2] << 16)) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
|
|
int xh = (Bytes[ReaderIndex + 7] << 24) | (Bytes[ReaderIndex + 6] << 16) | (Bytes[ReaderIndex + 5] << 8) | Bytes[ReaderIndex + 4];
|
|
x = ((long)xh << 32) | (long)xl;
|
|
#endif
|
|
ReaderIndex += 8;
|
|
return x;
|
|
}
|
|
|
|
private static unsafe void Copy8(byte* dst, byte* src)
|
|
{
|
|
dst[0] = src[0];
|
|
dst[1] = src[1];
|
|
dst[2] = src[2];
|
|
dst[3] = src[3];
|
|
dst[4] = src[4];
|
|
dst[5] = src[5];
|
|
dst[6] = src[6];
|
|
dst[7] = src[7];
|
|
}
|
|
|
|
private static unsafe void Copy4(byte* dst, byte* src)
|
|
{
|
|
dst[0] = src[0];
|
|
dst[1] = src[1];
|
|
dst[2] = src[2];
|
|
dst[3] = src[3];
|
|
}
|
|
|
|
|
|
//const bool isLittleEndian = true;
|
|
public void WriteFloat(float x)
|
|
{
|
|
EnsureWrite(4);
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[WriterIndex])
|
|
{
|
|
#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
if ((long)b % 4 == 0)
|
|
{
|
|
*(float*)b = x;
|
|
}
|
|
else
|
|
{
|
|
Copy4(b, (byte*)&x);
|
|
}
|
|
#else
|
|
*(float*)b = x;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//if (!BitConverter.IsLittleEndian)
|
|
//{
|
|
// Array.Reverse(data, endPos, 4);
|
|
//}
|
|
WriterIndex += 4;
|
|
}
|
|
|
|
public float ReadFloat()
|
|
{
|
|
EnsureRead(4);
|
|
//if (!BitConverter.IsLittleEndian)
|
|
//{
|
|
// Array.Reverse(data, beginPos, 4);
|
|
//}
|
|
float x;
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[ReaderIndex])
|
|
{
|
|
#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
if ((long)b % 4 == 0)
|
|
{
|
|
x = *(float*)b;
|
|
}
|
|
else
|
|
{
|
|
*((int*)&x) = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
|
|
}
|
|
#else
|
|
x = *(float*)b;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ReaderIndex += 4;
|
|
return x;
|
|
}
|
|
|
|
public void WriteDouble(double x)
|
|
{
|
|
EnsureWrite(8);
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[WriterIndex])
|
|
{
|
|
#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
if ((long)b % 8 == 0)
|
|
{
|
|
*(double*)b = x;
|
|
}
|
|
else
|
|
{
|
|
Copy8(b, (byte*)&x);
|
|
}
|
|
#else
|
|
*(double*)b = x;
|
|
#endif
|
|
}
|
|
//if (!BitConverter.IsLittleEndian)
|
|
//{
|
|
// Array.Reverse(data, endPos, 8);
|
|
//}
|
|
}
|
|
|
|
WriterIndex += 8;
|
|
}
|
|
|
|
public double ReadDouble()
|
|
{
|
|
EnsureRead(8);
|
|
//if (!BitConverter.IsLittleEndian)
|
|
//{
|
|
// Array.Reverse(data, beginPos, 8);
|
|
//}
|
|
double x;
|
|
unsafe
|
|
{
|
|
fixed (byte* b = &Bytes[ReaderIndex])
|
|
{
|
|
#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
|
|
if ((long)b % 8 == 0)
|
|
{
|
|
x = *(double*)b;
|
|
}
|
|
else
|
|
{
|
|
int low = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
|
|
int high = (b[4]) | (b[5] << 8) | (b[6] << 16) | (b[7] << 24);
|
|
*((long*)&x) = ((long)high << 32) | (uint)low;
|
|
}
|
|
#else
|
|
x = *(double*)b;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ReaderIndex += 8;
|
|
return x;
|
|
}
|
|
|
|
public void WriteSize(int n)
|
|
{
|
|
WriteUint((uint)n);
|
|
}
|
|
|
|
public int ReadSize()
|
|
{
|
|
return (int)ReadUint();
|
|
}
|
|
|
|
// marshal int
|
|
// n -> (n << 1) ^ (n >> 31)
|
|
// Read
|
|
// (x >>> 1) ^ ((x << 31) >> 31)
|
|
// (x >>> 1) ^ -(n&1)
|
|
public void WriteSint(int x)
|
|
{
|
|
WriteUint(((uint)x << 1) ^ ((uint)x >> 31));
|
|
}
|
|
|
|
public int ReadSint()
|
|
{
|
|
uint x = ReadUint();
|
|
return (int)((x >> 1) ^ ((x & 1) << 31));
|
|
}
|
|
|
|
|
|
// marshal long
|
|
// n -> (n << 1) ^ (n >> 63)
|
|
// Read
|
|
// (x >>> 1) ^((x << 63) >> 63)
|
|
// (x >>> 1) ^ -(n&1L)
|
|
public void WriteSlong(long x)
|
|
{
|
|
WriteUlong(((ulong)x << 1) ^ ((ulong)x >> 63));
|
|
}
|
|
|
|
public long ReadSlong()
|
|
{
|
|
long x = ReadLong();
|
|
return ((long)((ulong)x >> 1) ^ ((x & 1) << 63));
|
|
}
|
|
|
|
public void WriteString(string x)
|
|
{
|
|
var n = x != null ? Encoding.UTF8.GetByteCount(x) : 0;
|
|
WriteSize(n);
|
|
if (n > 0)
|
|
{
|
|
EnsureWrite(n);
|
|
Encoding.UTF8.GetBytes(x, 0, x.Length, Bytes, WriterIndex);
|
|
WriterIndex += n;
|
|
}
|
|
}
|
|
|
|
// byte[], [start, end)
|
|
public static Func<byte[], int, int, string> StringCacheFinder { get; set; }
|
|
|
|
public string ReadString()
|
|
{
|
|
var n = ReadSize();
|
|
if (n > 0)
|
|
{
|
|
EnsureRead(n);
|
|
string s;
|
|
|
|
if (StringCacheFinder == null)
|
|
{
|
|
s = Encoding.UTF8.GetString(Bytes, ReaderIndex, n);
|
|
}
|
|
else
|
|
{
|
|
// 只缓存比较小的字符串
|
|
s = StringCacheFinder(Bytes, ReaderIndex, n);
|
|
}
|
|
ReaderIndex += n;
|
|
return s;
|
|
}
|
|
else
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public void WriteBytes(byte[] x)
|
|
{
|
|
var n = x != null ? x.Length : 0;
|
|
WriteSize(n);
|
|
if (n > 0)
|
|
{
|
|
EnsureWrite(n);
|
|
x.CopyTo(Bytes, WriterIndex);
|
|
WriterIndex += n;
|
|
}
|
|
}
|
|
|
|
public byte[] ReadBytes()
|
|
{
|
|
var n = ReadSize();
|
|
if (n > 0)
|
|
{
|
|
EnsureRead(n);
|
|
var x = new byte[n];
|
|
Buffer.BlockCopy(Bytes, ReaderIndex, x, 0, n);
|
|
ReaderIndex += n;
|
|
return x;
|
|
}
|
|
else
|
|
{
|
|
return Array.Empty<byte>();
|
|
}
|
|
}
|
|
|
|
// 以下是一些特殊类型
|
|
|
|
public void WriteComplex(Complex x)
|
|
{
|
|
WriteDouble(x.Real);
|
|
WriteDouble(x.Imaginary);
|
|
}
|
|
|
|
public Complex ReadComplex()
|
|
{
|
|
var x = ReadDouble();
|
|
var y = ReadDouble();
|
|
return new Complex(x, y);
|
|
}
|
|
|
|
public void WriteVector2(Vector2 x)
|
|
{
|
|
WriteFloat(x.X);
|
|
WriteFloat(x.Y);
|
|
}
|
|
|
|
public Vector2 ReadVector2()
|
|
{
|
|
float x = ReadFloat();
|
|
float y = ReadFloat();
|
|
return new Vector2(x, y);
|
|
}
|
|
|
|
public void WriteVector3(Vector3 x)
|
|
{
|
|
WriteFloat(x.X);
|
|
WriteFloat(x.Y);
|
|
WriteFloat(x.Z);
|
|
}
|
|
|
|
public Vector3 ReadVector3()
|
|
{
|
|
float x = ReadFloat();
|
|
float y = ReadFloat();
|
|
float z = ReadFloat();
|
|
return new Vector3(x, y, z);
|
|
}
|
|
|
|
public void WriteVector4(Vector4 x)
|
|
{
|
|
WriteFloat(x.X);
|
|
WriteFloat(x.Y);
|
|
WriteFloat(x.Z);
|
|
WriteFloat(x.W);
|
|
}
|
|
|
|
public Vector4 ReadVector4()
|
|
{
|
|
float x = ReadFloat();
|
|
float y = ReadFloat();
|
|
float z = ReadFloat();
|
|
float w = ReadFloat();
|
|
return new Vector4(x, y, z, w);
|
|
}
|
|
|
|
|
|
public void WriteQuaternion(Quaternion x)
|
|
{
|
|
WriteFloat(x.X);
|
|
WriteFloat(x.Y);
|
|
WriteFloat(x.Z);
|
|
WriteFloat(x.W);
|
|
}
|
|
|
|
public Quaternion ReadQuaternion()
|
|
{
|
|
float x = ReadFloat();
|
|
float y = ReadFloat();
|
|
float z = ReadFloat();
|
|
float w = ReadFloat();
|
|
return new Quaternion(x, y, z, w);
|
|
}
|
|
|
|
|
|
public void WriteMatrix4x4(Matrix4x4 x)
|
|
{
|
|
WriteFloat(x.M11);
|
|
WriteFloat(x.M12);
|
|
WriteFloat(x.M13);
|
|
WriteFloat(x.M14);
|
|
WriteFloat(x.M21);
|
|
WriteFloat(x.M22);
|
|
WriteFloat(x.M23);
|
|
WriteFloat(x.M24);
|
|
WriteFloat(x.M31);
|
|
WriteFloat(x.M32);
|
|
WriteFloat(x.M33);
|
|
WriteFloat(x.M34);
|
|
WriteFloat(x.M41);
|
|
WriteFloat(x.M42);
|
|
WriteFloat(x.M43);
|
|
WriteFloat(x.M44);
|
|
}
|
|
|
|
public Matrix4x4 ReadMatrix4x4()
|
|
{
|
|
float m11 = ReadFloat();
|
|
float m12 = ReadFloat();
|
|
float m13 = ReadFloat();
|
|
float m14 = ReadFloat();
|
|
float m21 = ReadFloat();
|
|
float m22 = ReadFloat();
|
|
float m23 = ReadFloat();
|
|
float m24 = ReadFloat();
|
|
float m31 = ReadFloat();
|
|
float m32 = ReadFloat();
|
|
float m33 = ReadFloat();
|
|
float m34 = ReadFloat();
|
|
float m41 = ReadFloat();
|
|
float m42 = ReadFloat();
|
|
float m43 = ReadFloat();
|
|
float m44 = ReadFloat();
|
|
return new Matrix4x4(m11, m12, m13, m14,
|
|
m21, m22, m23, m24,
|
|
m31, m32, m33, m34,
|
|
m41, m42, m43, m44);
|
|
}
|
|
|
|
internal void SkipBytes()
|
|
{
|
|
int n = ReadSize();
|
|
EnsureRead(n);
|
|
ReaderIndex += n;
|
|
}
|
|
|
|
|
|
public void WriteByteBufWithSize(ByteBuf o)
|
|
{
|
|
int n = o.Size;
|
|
if (n > 0)
|
|
{
|
|
WriteSize(n);
|
|
WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n);
|
|
}
|
|
else
|
|
{
|
|
WriteByte(0);
|
|
}
|
|
}
|
|
|
|
public void WriteByteBufWithoutSize(ByteBuf o)
|
|
{
|
|
int n = o.Size;
|
|
if (n > 0)
|
|
{
|
|
WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n);
|
|
}
|
|
}
|
|
|
|
public bool TryReadByte(out byte x)
|
|
{
|
|
if (CanRead(1))
|
|
{
|
|
x = Bytes[ReaderIndex++];
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
x = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public EDeserializeError TryDeserializeInplaceByteBuf(int maxSize, ByteBuf inplaceTempBody)
|
|
{
|
|
//if (!CanRead(1)) { return EDeserializeError.NOT_ENOUGH; }
|
|
int oldReadIndex = ReaderIndex;
|
|
bool commit = false;
|
|
try
|
|
{
|
|
int n;
|
|
int h = Bytes[ReaderIndex];
|
|
if (h < 0x80)
|
|
{
|
|
ReaderIndex++;
|
|
n = h;
|
|
}
|
|
else if (h < 0xc0)
|
|
{
|
|
if (!CanRead(2)) { return EDeserializeError.NOT_ENOUGH; }
|
|
n = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
|
|
ReaderIndex += 2;
|
|
}
|
|
else if (h < 0xe0)
|
|
{
|
|
if (!CanRead(3)) { return EDeserializeError.NOT_ENOUGH; }
|
|
n = ((h & 0x1f) << 16) | (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
ReaderIndex += 3;
|
|
}
|
|
else if (h < 0xf0)
|
|
{
|
|
if (!CanRead(4)) { return EDeserializeError.NOT_ENOUGH; }
|
|
n = ((h & 0x0f) << 24) | (Bytes[ReaderIndex + 1] << 16) | (Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
|
|
ReaderIndex += 4;
|
|
}
|
|
else
|
|
{
|
|
return EDeserializeError.EXCEED_SIZE;
|
|
}
|
|
|
|
if (n > maxSize)
|
|
{
|
|
return EDeserializeError.EXCEED_SIZE;
|
|
}
|
|
if (Remaining < n)
|
|
{
|
|
return EDeserializeError.NOT_ENOUGH;
|
|
}
|
|
|
|
int inplaceReadIndex = ReaderIndex;
|
|
ReaderIndex += n;
|
|
|
|
inplaceTempBody.Replace(Bytes, inplaceReadIndex, ReaderIndex);
|
|
commit = true;
|
|
}
|
|
finally
|
|
{
|
|
if (!commit)
|
|
{
|
|
ReaderIndex = oldReadIndex;
|
|
}
|
|
}
|
|
|
|
return EDeserializeError.OK;
|
|
}
|
|
|
|
public void WriteRawTag(byte b1)
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex++] = b1;
|
|
}
|
|
|
|
public void WriteRawTag(byte b1, byte b2)
|
|
{
|
|
EnsureWrite(2);
|
|
Bytes[WriterIndex] = b1;
|
|
Bytes[WriterIndex + 1] = b2;
|
|
WriterIndex += 2;
|
|
}
|
|
|
|
public void WriteRawTag(byte b1, byte b2, byte b3)
|
|
{
|
|
EnsureWrite(3);
|
|
Bytes[WriterIndex] = b1;
|
|
Bytes[WriterIndex + 1] = b2;
|
|
Bytes[WriterIndex + 2] = b3;
|
|
WriterIndex += 3;
|
|
}
|
|
|
|
#region segment
|
|
|
|
|
|
public void BeginWriteSegment(out int oldSize)
|
|
{
|
|
oldSize = Size;
|
|
EnsureWrite(1);
|
|
WriterIndex += 1;
|
|
}
|
|
|
|
public void EndWriteSegment(int oldSize)
|
|
{
|
|
int startPos = ReaderIndex + oldSize;
|
|
int segmentSize = WriterIndex - startPos - 1;
|
|
|
|
// 0 111 1111
|
|
if (segmentSize < 0x80)
|
|
{
|
|
Bytes[startPos] = (byte)segmentSize;
|
|
}
|
|
else if (segmentSize < 0x4000) // 10 11 1111, -
|
|
{
|
|
EnsureWrite(1);
|
|
Bytes[WriterIndex] = Bytes[startPos + 1];
|
|
Bytes[startPos + 1] = (byte)segmentSize;
|
|
|
|
Bytes[startPos] = (byte)((segmentSize >> 8) | 0x80);
|
|
WriterIndex += 1;
|
|
}
|
|
else if (segmentSize < 0x200000) // 110 1 1111, -,-
|
|
{
|
|
EnsureWrite(2);
|
|
Bytes[WriterIndex + 1] = Bytes[startPos + 2];
|
|
Bytes[startPos + 2] = (byte)segmentSize;
|
|
|
|
Bytes[WriterIndex] = Bytes[startPos + 1];
|
|
Bytes[startPos + 1] = (byte)(segmentSize >> 8);
|
|
|
|
Bytes[startPos] = (byte)((segmentSize >> 16) | 0xc0);
|
|
WriterIndex += 2;
|
|
}
|
|
else if (segmentSize < 0x10000000) // 1110 1111,-,-,-
|
|
{
|
|
EnsureWrite(3);
|
|
Bytes[WriterIndex + 2] = Bytes[startPos + 3];
|
|
Bytes[startPos + 3] = (byte)segmentSize;
|
|
|
|
Bytes[WriterIndex + 1] = Bytes[startPos + 2];
|
|
Bytes[startPos + 2] = (byte)(segmentSize >> 8);
|
|
|
|
Bytes[WriterIndex] = Bytes[startPos + 1];
|
|
Bytes[startPos + 1] = (byte)(segmentSize >> 16);
|
|
|
|
Bytes[startPos] = (byte)((segmentSize >> 24) | 0xe0);
|
|
WriterIndex += 3;
|
|
}
|
|
else
|
|
{
|
|
throw new SerializationException("exceed max segment size");
|
|
}
|
|
}
|
|
|
|
public void ReadSegment(out int startIndex, out int segmentSize)
|
|
{
|
|
EnsureRead(1);
|
|
int h = Bytes[ReaderIndex++];
|
|
|
|
startIndex = ReaderIndex;
|
|
|
|
if (h < 0x80)
|
|
{
|
|
segmentSize = h;
|
|
ReaderIndex += segmentSize;
|
|
}
|
|
else if (h < 0xc0)
|
|
{
|
|
EnsureRead(1);
|
|
segmentSize = ((h & 0x3f) << 8) | Bytes[ReaderIndex];
|
|
int endPos = ReaderIndex + segmentSize;
|
|
Bytes[ReaderIndex] = Bytes[endPos];
|
|
ReaderIndex += segmentSize + 1;
|
|
}
|
|
else if (h < 0xe0)
|
|
{
|
|
EnsureRead(2);
|
|
segmentSize = ((h & 0x1f) << 16) | ((int)Bytes[ReaderIndex] << 8) | Bytes[ReaderIndex + 1];
|
|
int endPos = ReaderIndex + segmentSize;
|
|
Bytes[ReaderIndex] = Bytes[endPos];
|
|
Bytes[ReaderIndex + 1] = Bytes[endPos + 1];
|
|
ReaderIndex += segmentSize + 2;
|
|
}
|
|
else if (h < 0xf0)
|
|
{
|
|
EnsureRead(3);
|
|
segmentSize = ((h & 0x0f) << 24) | ((int)Bytes[ReaderIndex] << 16) | ((int)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
|
|
int endPos = ReaderIndex + segmentSize;
|
|
Bytes[ReaderIndex] = Bytes[endPos];
|
|
Bytes[ReaderIndex + 1] = Bytes[endPos + 1];
|
|
Bytes[ReaderIndex + 2] = Bytes[endPos + 2];
|
|
ReaderIndex += segmentSize + 3;
|
|
}
|
|
else
|
|
{
|
|
throw new SerializationException("exceed max size");
|
|
}
|
|
if (ReaderIndex > WriterIndex)
|
|
{
|
|
throw new SerializationException("segment data not enough");
|
|
}
|
|
}
|
|
|
|
public void ReadSegment(ByteBuf buf)
|
|
{
|
|
ReadSegment(out int startPos, out var size);
|
|
buf.Bytes = Bytes;
|
|
buf.ReaderIndex = startPos;
|
|
buf.WriterIndex = startPos + size;
|
|
}
|
|
|
|
public void EnterSegment(out SegmentSaveState saveState)
|
|
{
|
|
ReadSegment(out int startPos, out int size);
|
|
|
|
saveState = new SegmentSaveState(ReaderIndex, WriterIndex);
|
|
ReaderIndex = startPos;
|
|
WriterIndex = startPos + size;
|
|
}
|
|
|
|
public void LeaveSegment(SegmentSaveState saveState)
|
|
{
|
|
ReaderIndex = saveState.ReaderIndex;
|
|
WriterIndex = saveState.WriterIndex;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override string ToString()
|
|
{
|
|
string[] datas = new string[WriterIndex - ReaderIndex];
|
|
for (var i = ReaderIndex; i < WriterIndex; i++)
|
|
{
|
|
datas[i - ReaderIndex] = Bytes[i].ToString("X2");
|
|
}
|
|
return string.Join(".", datas);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return (obj is ByteBuf other) && Equals(other);
|
|
}
|
|
|
|
public bool Equals(ByteBuf other)
|
|
{
|
|
if (other == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (Size != other.Size)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0, n = Size; i < n; i++)
|
|
{
|
|
if (Bytes[ReaderIndex + i] != other.Bytes[other.ReaderIndex + i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public object Clone()
|
|
{
|
|
return new ByteBuf(CopyData());
|
|
}
|
|
|
|
|
|
public static ByteBuf FromString(string value)
|
|
{
|
|
var ss = value.Split(',');
|
|
byte[] data = new byte[ss.Length];
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
data[i] = byte.Parse(ss[i]);
|
|
}
|
|
return new ByteBuf(data);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
int hash = 17;
|
|
for (int i = ReaderIndex; i < WriterIndex; i++)
|
|
{
|
|
hash = hash * 23 + Bytes[i];
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
_releaser?.Invoke(this);
|
|
}
|
|
|
|
#if SUPPORT_PUERTS_ARRAYBUF
|
|
// -- add for puerts
|
|
public Puerts.ArrayBuffer ReadArrayBuffer()
|
|
{
|
|
return new Puerts.ArrayBuffer(ReadBytes());
|
|
}
|
|
|
|
public void WriteArrayBuffer(Puerts.ArrayBuffer bytes)
|
|
{
|
|
WriteBytes(bytes.Bytes);
|
|
}
|
|
#endif
|
|
}
|
|
}
|