Files
ichni_Official/Packages/com.tivadar.best.http/Runtime/Shared/Database/Utils/StreamUtil.cs
2026-06-15 18:18:16 +08:00

134 lines
4.1 KiB
C#

using System;
using System.IO;
using System.Text;
using Best.HTTP.Shared.PlatformSupport.Memory;
namespace Best.HTTP.Shared.Databases.Utils
{
public static class StreamUtil
{
public static void WriteLengthPrefixedString(this Stream stream, string str)
{
if (str != null)
{
var byteCount = Encoding.UTF8.GetByteCount(str);
if (byteCount >= 1 << 16)
throw new ArgumentException($"byteCount({byteCount})");
stream.EncodeUnsignedVariableByteInteger((ulong)byteCount);
byte[] tmp = BufferPool.Get(byteCount, true);
Encoding.UTF8.GetBytes(str, 0, str.Length, tmp, 0);
stream.Write(tmp, 0, byteCount);
BufferPool.Release(tmp);
}
else
{
stream.WriteByte(0);
}
}
public static string ReadLengthPrefixedString(this Stream stream)
{
int strLength = (int)stream.DecodeUnsignedVariableByteInteger();
string result = null;
if (strLength != 0)
{
byte[] buffer = BufferPool.Get(strLength, true);
stream.Read(buffer, 0, strLength);
result = System.Text.Encoding.UTF8.GetString(buffer, 0, strLength);
BufferPool.Release(buffer);
}
return result;
}
public static void EncodeUnsignedVariableByteInteger(this Stream encodeTo, ulong value)
{
if (value < 0)
throw new NotSupportedException($"Can't encode negative value({value:N0})!");
byte encodedByte;
do
{
encodedByte = (byte)(value % 128);
value /= 128;
// if there are more data to encode, set the top bit of this byte
if (value > 0)
encodedByte = (byte)(encodedByte | 128);
encodeTo.WriteByte(encodedByte);
}
while (value > 0);
}
public static ulong DecodeUnsignedVariableByteInteger(this Stream decodeFrom)
{
ulong multiplier = 1;
ulong value = 0;
byte encodedByte = 0;
do
{
encodedByte = (byte)decodeFrom.ReadByte();
value += (ulong)((ulong)(encodedByte & 127) * multiplier);
multiplier *= 128;
} while ((encodedByte & 128) != 0);
return value;
}
public static void EncodeSignedVariableByteInteger(this Stream encodeTo, long value)
{
bool more = true;
while (more)
{
byte chunk = (byte)(value & 0x7fL); // extract a 7-bit chunk
value >>= 7;
bool signBitSet = (chunk & 0x40) != 0; // sign bit is the msb of a 7-bit byte, so 0x40
more = !((value == 0 && !signBitSet) || (value == -1 && signBitSet));
if (more) { chunk |= 0x80; } // set msb marker that more bytes are coming
encodeTo.WriteByte(chunk);
};
}
public static long DecodeSignedVariableByteInteger(this Stream stream)
{
long value = 0;
int shift = 0;
bool more = true;
bool signBitSet = false;
while (more)
{
var next = stream.ReadByte();
if (next < 0)
throw new InvalidOperationException("Unexpected end of stream");
byte b = (byte)next;
more = (b & 0x80) != 0; // extract msb
signBitSet = (b & 0x40) != 0; // sign bit is the msb of a 7-bit byte, so 0x40
long chunk = b & 0x7fL; // extract lower 7 bits
value |= chunk << shift;
shift += 7;
};
// extend the sign of shorter negative numbers
if (shift < (sizeof(long) * 8) && signBitSet) { value |= -1L << shift; }
return value;
}
}
}