Files
PURErat-crack-scode/decompiled/PanelPlugins/PureHelper.Client/ProtoBuf/ProtoWriter.cs
T
2026-08-27 10:56:38 -06:00

954 lines
22 KiB
C#

using System;
using System.IO;
using System.Text;
using ProtoBuf.Meta;
namespace ProtoBuf;
public sealed class ProtoWriter : IDisposable
{
private Stream dest;
private TypeModel model;
private readonly NetObjectCache netCache = new NetObjectCache();
private int fieldNumber;
private int flushLock;
private WireType wireType;
private int depth;
private const int RecursionCheckDepth = 25;
private MutableList recursionStack;
private readonly SerializationContext context;
private byte[] ioBuffer;
private int ioIndex;
private long position64;
private static readonly UTF8Encoding encoding = new UTF8Encoding();
private int packedFieldNumber;
internal NetObjectCache NetCache => netCache;
internal WireType WireType => wireType;
public SerializationContext Context => context;
public TypeModel Model => model;
public static void WriteObject(object value, int key, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
SubItemToken token = StartSubItem(value, writer);
if (key >= 0)
{
writer.model.Serialize(key, value, writer);
}
else if (writer.model == null || !writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, 1, value, isInsideList: false, null))
{
TypeModel.ThrowUnexpectedType(value.GetType());
}
EndSubItem(token, writer);
}
public static void WriteRecursionSafeObject(object value, int key, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
SubItemToken token = StartSubItem(null, writer);
writer.model.Serialize(key, value, writer);
EndSubItem(token, writer);
}
internal static void WriteObject(object value, int key, ProtoWriter writer, PrefixStyle style, int fieldNumber)
{
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
if (writer.wireType != WireType.None)
{
throw CreateException(writer);
}
switch (style)
{
case PrefixStyle.Base128:
writer.wireType = WireType.String;
writer.fieldNumber = fieldNumber;
if (fieldNumber > 0)
{
WriteHeaderCore(fieldNumber, WireType.String, writer);
}
break;
case PrefixStyle.Fixed32:
case PrefixStyle.Fixed32BigEndian:
writer.fieldNumber = 0;
writer.wireType = WireType.Fixed32;
break;
default:
throw new ArgumentOutOfRangeException("style");
}
SubItemToken token = StartSubItem(value, writer, allowFixed: true);
if (key < 0)
{
if (!writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, 1, value, isInsideList: false, null))
{
TypeModel.ThrowUnexpectedType(value.GetType());
}
}
else
{
writer.model.Serialize(key, value, writer);
}
EndSubItem(token, writer, style);
}
internal int GetTypeKey(ref Type type)
{
return model.GetKey(ref type);
}
public static void WriteFieldHeader(int fieldNumber, WireType wireType, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.wireType != WireType.None)
{
throw new InvalidOperationException("Cannot write a " + wireType.ToString() + " header until the " + writer.wireType.ToString() + " data has been written");
}
if (fieldNumber < 0)
{
throw new ArgumentOutOfRangeException("fieldNumber");
}
if (writer.packedFieldNumber == 0)
{
writer.fieldNumber = fieldNumber;
writer.wireType = wireType;
WriteHeaderCore(fieldNumber, wireType, writer);
return;
}
if (writer.packedFieldNumber == fieldNumber)
{
if ((uint)wireType > 1u && wireType != WireType.Fixed32 && wireType != WireType.SignedVariant)
{
throw new InvalidOperationException("Wire-type cannot be encoded as packed: " + wireType);
}
writer.fieldNumber = fieldNumber;
writer.wireType = wireType;
return;
}
throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber + " but received " + fieldNumber);
}
internal static void WriteHeaderCore(int fieldNumber, WireType wireType, ProtoWriter writer)
{
uint value = (uint)(fieldNumber << 3) | (uint)(wireType & (WireType)7);
WriteUInt32Variant(value, writer);
}
public static void WriteBytes(byte[] data, ProtoWriter writer)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
WriteBytes(data, 0, data.Length, writer);
}
public static void WriteBytes(byte[] data, int offset, int length, ProtoWriter writer)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed32:
if (length != 4)
{
throw new ArgumentException("length");
}
break;
case WireType.Fixed64:
if (length != 8)
{
throw new ArgumentException("length");
}
break;
case WireType.String:
WriteUInt32Variant((uint)length, writer);
writer.wireType = WireType.None;
if (length == 0)
{
return;
}
if (writer.flushLock == 0 && length > writer.ioBuffer.Length)
{
Flush(writer);
writer.dest.Write(data, offset, length);
writer.position64 += length;
return;
}
break;
default:
throw CreateException(writer);
}
DemandSpace(length, writer);
Buffer.BlockCopy(data, offset, writer.ioBuffer, writer.ioIndex, length);
IncrementedAndReset(length, writer);
}
private static void CopyRawFromStream(Stream source, ProtoWriter writer)
{
byte[] array = writer.ioBuffer;
int num = array.Length - writer.ioIndex;
int num2 = 1;
while (num > 0 && (num2 = source.Read(array, writer.ioIndex, num)) > 0)
{
writer.ioIndex += num2;
writer.position64 += num2;
num -= num2;
}
if (num2 <= 0)
{
return;
}
if (writer.flushLock == 0)
{
Flush(writer);
while ((num2 = source.Read(array, 0, array.Length)) > 0)
{
writer.dest.Write(array, 0, num2);
writer.position64 += num2;
}
return;
}
while (true)
{
DemandSpace(128, writer);
if ((num2 = source.Read(writer.ioBuffer, writer.ioIndex, writer.ioBuffer.Length - writer.ioIndex)) > 0)
{
writer.position64 += num2;
writer.ioIndex += num2;
continue;
}
break;
}
}
private static void IncrementedAndReset(int length, ProtoWriter writer)
{
writer.ioIndex += length;
writer.position64 += length;
writer.wireType = WireType.None;
}
public static SubItemToken StartSubItem(object instance, ProtoWriter writer)
{
return StartSubItem(instance, writer, allowFixed: false);
}
private void CheckRecursionStackAndPush(object instance)
{
int num;
if (recursionStack == null)
{
recursionStack = new MutableList();
}
else if (instance != null && (num = recursionStack.IndexOfReference(instance)) >= 0)
{
throw new ProtoException("Possible recursion detected (offset: " + (recursionStack.Count - num) + " level(s)): " + instance.ToString());
}
recursionStack.Add(instance);
}
private void PopRecursionStack()
{
recursionStack.RemoveLast();
}
private static SubItemToken StartSubItem(object instance, ProtoWriter writer, bool allowFixed)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (++writer.depth > 25)
{
writer.CheckRecursionStackAndPush(instance);
}
if (writer.packedFieldNumber != 0)
{
throw new InvalidOperationException("Cannot begin a sub-item while performing packed encoding");
}
switch (writer.wireType)
{
case WireType.StartGroup:
writer.wireType = WireType.None;
return new SubItemToken((long)(-writer.fieldNumber));
case WireType.String:
writer.wireType = WireType.None;
DemandSpace(32, writer);
writer.flushLock++;
writer.position64++;
return new SubItemToken((long)writer.ioIndex++);
case WireType.Fixed32:
{
if (!allowFixed)
{
throw CreateException(writer);
}
DemandSpace(32, writer);
writer.flushLock++;
SubItemToken result = new SubItemToken((long)writer.ioIndex);
IncrementedAndReset(4, writer);
return result;
}
default:
throw CreateException(writer);
}
}
public static void EndSubItem(SubItemToken token, ProtoWriter writer)
{
EndSubItem(token, writer, PrefixStyle.Base128);
}
private static void EndSubItem(SubItemToken token, ProtoWriter writer, PrefixStyle style)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.wireType != WireType.None)
{
throw CreateException(writer);
}
int num = (int)token.value64;
if (writer.depth <= 0)
{
throw CreateException(writer);
}
if (writer.depth-- > 25)
{
writer.PopRecursionStack();
}
writer.packedFieldNumber = 0;
if (num < 0)
{
WriteHeaderCore(-num, WireType.EndGroup, writer);
writer.wireType = WireType.None;
return;
}
switch (style)
{
case PrefixStyle.Fixed32:
{
int num2 = writer.ioIndex - num - 4;
WriteInt32ToBuffer(num2, writer.ioBuffer, num);
break;
}
case PrefixStyle.Fixed32BigEndian:
{
int num2 = writer.ioIndex - num - 4;
byte[] array2 = writer.ioBuffer;
WriteInt32ToBuffer(num2, array2, num);
byte b = array2[num];
array2[num] = array2[num + 3];
array2[num + 3] = b;
b = array2[num + 1];
array2[num + 1] = array2[num + 2];
array2[num + 2] = b;
break;
}
case PrefixStyle.Base128:
{
int num2 = writer.ioIndex - num - 1;
int num3 = 0;
uint num4 = (uint)num2;
while ((num4 >>= 7) != 0)
{
num3++;
}
if (num3 == 0)
{
writer.ioBuffer[num] = (byte)(num2 & 0x7F);
break;
}
DemandSpace(num3, writer);
byte[] array = writer.ioBuffer;
Buffer.BlockCopy(array, num + 1, array, num + 1 + num3, num2);
num4 = (uint)num2;
do
{
array[num++] = (byte)((num4 & 0x7F) | 0x80);
}
while ((num4 >>= 7) != 0);
array[num - 1] = (byte)(array[num - 1] & -129);
writer.position64 += num3;
writer.ioIndex += num3;
break;
}
default:
throw new ArgumentOutOfRangeException("style");
}
if (--writer.flushLock == 0 && writer.ioIndex >= 1024)
{
Flush(writer);
}
}
public static ProtoWriter Create(Stream dest, TypeModel model, SerializationContext context = null)
{
return new ProtoWriter(dest, model, context);
}
[Obsolete("Please use ProtoWriter.Create; this API may be removed in a future version", false)]
public ProtoWriter(Stream dest, TypeModel model, SerializationContext context)
{
if (dest == null)
{
throw new ArgumentNullException("dest");
}
if (!dest.CanWrite)
{
throw new ArgumentException("Cannot write to stream", "dest");
}
this.dest = dest;
ioBuffer = BufferPool.GetBuffer();
this.model = model;
wireType = WireType.None;
if (context == null)
{
context = SerializationContext.Default;
}
else
{
context.Freeze();
}
this.context = context;
}
void IDisposable.Dispose()
{
Dispose();
}
private void Dispose()
{
if (dest != null)
{
Flush(this);
dest = null;
}
model = null;
BufferPool.ReleaseBufferToPool(ref ioBuffer);
}
internal static long GetLongPosition(ProtoWriter writer)
{
return writer.position64;
}
internal static int GetPosition(ProtoWriter writer)
{
return checked((int)writer.position64);
}
private static void DemandSpace(int required, ProtoWriter writer)
{
if (writer.ioBuffer.Length - writer.ioIndex < required)
{
TryFlushOrResize(required, writer);
}
}
private static void TryFlushOrResize(int required, ProtoWriter writer)
{
if (writer.flushLock == 0)
{
Flush(writer);
if (writer.ioBuffer.Length - writer.ioIndex >= required)
{
return;
}
}
BufferPool.ResizeAndFlushLeft(ref writer.ioBuffer, required + writer.ioIndex, 0, writer.ioIndex);
}
public void Close()
{
if (depth != 0 || flushLock != 0)
{
throw new InvalidOperationException("Unable to close stream in an incomplete state");
}
Dispose();
}
internal void CheckDepthFlushlock()
{
if (depth != 0 || flushLock != 0)
{
throw new InvalidOperationException("The writer is in an incomplete state");
}
}
internal static void Flush(ProtoWriter writer)
{
if (writer.flushLock == 0 && writer.ioIndex != 0)
{
writer.dest.Write(writer.ioBuffer, 0, writer.ioIndex);
writer.ioIndex = 0;
}
}
private static void WriteUInt32Variant(uint value, ProtoWriter writer)
{
DemandSpace(5, writer);
int num = 0;
do
{
writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
num++;
}
while ((value >>= 7) != 0);
writer.ioBuffer[writer.ioIndex - 1] &= 127;
writer.position64 += num;
}
internal static uint Zig(int value)
{
return (uint)((value << 1) ^ (value >> 31));
}
internal static ulong Zig(long value)
{
return (ulong)((value << 1) ^ (value >> 63));
}
private static void WriteUInt64Variant(ulong value, ProtoWriter writer)
{
DemandSpace(10, writer);
int num = 0;
do
{
writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
num++;
}
while ((value >>= 7) != 0L);
writer.ioBuffer[writer.ioIndex - 1] &= 127;
writer.position64 += num;
}
public static void WriteString(string value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.wireType != WireType.String)
{
throw CreateException(writer);
}
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.Length == 0)
{
WriteUInt32Variant(0u, writer);
writer.wireType = WireType.None;
return;
}
int byteCount = encoding.GetByteCount(value);
WriteUInt32Variant((uint)byteCount, writer);
DemandSpace(byteCount, writer);
int bytes = encoding.GetBytes(value, 0, value.Length, writer.ioBuffer, writer.ioIndex);
IncrementedAndReset(bytes, writer);
}
public static void WriteUInt64(ulong value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed64:
WriteInt64((long)value, writer);
break;
case WireType.Variant:
WriteUInt64Variant(value, writer);
writer.wireType = WireType.None;
break;
case WireType.Fixed32:
WriteUInt32(checked((uint)value), writer);
break;
default:
throw CreateException(writer);
}
}
public static void WriteInt64(long value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed64:
{
DemandSpace(8, writer);
byte[] array = writer.ioBuffer;
int num = writer.ioIndex;
array[num] = (byte)value;
array[num + 1] = (byte)(value >> 8);
array[num + 2] = (byte)(value >> 16);
array[num + 3] = (byte)(value >> 24);
array[num + 4] = (byte)(value >> 32);
array[num + 5] = (byte)(value >> 40);
array[num + 6] = (byte)(value >> 48);
array[num + 7] = (byte)(value >> 56);
IncrementedAndReset(8, writer);
break;
}
case WireType.SignedVariant:
WriteUInt64Variant(Zig(value), writer);
writer.wireType = WireType.None;
break;
case WireType.Variant:
{
if (value >= 0)
{
WriteUInt64Variant((ulong)value, writer);
writer.wireType = WireType.None;
break;
}
DemandSpace(10, writer);
byte[] array = writer.ioBuffer;
int num = writer.ioIndex;
array[num] = (byte)(value | 0x80);
array[num + 1] = (byte)((int)(value >> 7) | 0x80);
array[num + 2] = (byte)((int)(value >> 14) | 0x80);
array[num + 3] = (byte)((int)(value >> 21) | 0x80);
array[num + 4] = (byte)((int)(value >> 28) | 0x80);
array[num + 5] = (byte)((int)(value >> 35) | 0x80);
array[num + 6] = (byte)((int)(value >> 42) | 0x80);
array[num + 7] = (byte)((int)(value >> 49) | 0x80);
array[num + 8] = (byte)((int)(value >> 56) | 0x80);
array[num + 9] = 1;
IncrementedAndReset(10, writer);
break;
}
case WireType.Fixed32:
WriteInt32(checked((int)value), writer);
break;
default:
throw CreateException(writer);
}
}
public static void WriteUInt32(uint value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed32:
WriteInt32((int)value, writer);
break;
case WireType.Fixed64:
WriteInt64((int)value, writer);
break;
case WireType.Variant:
WriteUInt32Variant(value, writer);
writer.wireType = WireType.None;
break;
default:
throw CreateException(writer);
}
}
public static void WriteInt16(short value, ProtoWriter writer)
{
WriteInt32(value, writer);
}
public static void WriteUInt16(ushort value, ProtoWriter writer)
{
WriteUInt32(value, writer);
}
public static void WriteByte(byte value, ProtoWriter writer)
{
WriteUInt32(value, writer);
}
public static void WriteSByte(sbyte value, ProtoWriter writer)
{
WriteInt32(value, writer);
}
private static void WriteInt32ToBuffer(int value, byte[] buffer, int index)
{
buffer[index] = (byte)value;
buffer[index + 1] = (byte)(value >> 8);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 3] = (byte)(value >> 24);
}
public static void WriteInt32(int value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed32:
DemandSpace(4, writer);
WriteInt32ToBuffer(value, writer.ioBuffer, writer.ioIndex);
IncrementedAndReset(4, writer);
break;
case WireType.Fixed64:
{
DemandSpace(8, writer);
byte[] array = writer.ioBuffer;
int num = writer.ioIndex;
array[num] = (byte)value;
array[num + 1] = (byte)(value >> 8);
array[num + 2] = (byte)(value >> 16);
array[num + 3] = (byte)(value >> 24);
array[num + 4] = (array[num + 5] = (array[num + 6] = (array[num + 7] = 0)));
IncrementedAndReset(8, writer);
break;
}
case WireType.SignedVariant:
WriteUInt32Variant(Zig(value), writer);
writer.wireType = WireType.None;
break;
case WireType.Variant:
{
if (value >= 0)
{
WriteUInt32Variant((uint)value, writer);
writer.wireType = WireType.None;
break;
}
DemandSpace(10, writer);
byte[] array = writer.ioBuffer;
int num = writer.ioIndex;
array[num] = (byte)(value | 0x80);
array[num + 1] = (byte)((value >> 7) | 0x80);
array[num + 2] = (byte)((value >> 14) | 0x80);
array[num + 3] = (byte)((value >> 21) | 0x80);
array[num + 4] = (byte)((value >> 28) | 0x80);
byte[] array2 = array;
int num2 = num + 5;
byte[] array3 = array;
int num3 = num + 6;
byte[] array4 = array;
int num4 = num + 7;
byte b;
array[num + 8] = (b = byte.MaxValue);
array2[num2] = (array3[num3] = (array4[num4] = b));
array[num + 9] = 1;
IncrementedAndReset(10, writer);
break;
}
default:
throw CreateException(writer);
}
}
public unsafe static void WriteDouble(double value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed32:
{
float num = (float)value;
if (float.IsInfinity(num) && !double.IsInfinity(value))
{
throw new OverflowException();
}
WriteSingle(num, writer);
break;
}
case WireType.Fixed64:
WriteInt64(*(long*)(&value), writer);
break;
default:
throw CreateException(writer);
}
}
public unsafe static void WriteSingle(float value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
switch (writer.wireType)
{
case WireType.Fixed32:
WriteInt32(*(int*)(&value), writer);
break;
case WireType.Fixed64:
WriteDouble(value, writer);
break;
default:
throw CreateException(writer);
}
}
public static void ThrowEnumException(ProtoWriter writer, object enumValue)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
string text = ((enumValue == null) ? "<null>" : (enumValue.GetType().FullName + "." + enumValue.ToString()));
throw new ProtoException("No wire-value is mapped to the enum " + text + " at position " + writer.position64);
}
internal static Exception CreateException(ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
return new ProtoException("Invalid serialization operation with wire-type " + writer.wireType.ToString() + " at position " + writer.position64);
}
public static void WriteBoolean(bool value, ProtoWriter writer)
{
WriteUInt32(value ? 1u : 0u, writer);
}
public static void AppendExtensionData(IExtensible instance, ProtoWriter writer)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (writer == null)
{
throw new ArgumentNullException("writer");
}
if (writer.wireType != WireType.None)
{
throw CreateException(writer);
}
IExtension extensionObject = instance.GetExtensionObject(createIfMissing: false);
if (extensionObject != null)
{
Stream stream = extensionObject.BeginQuery();
try
{
CopyRawFromStream(stream, writer);
}
finally
{
extensionObject.EndQuery(stream);
}
}
}
public static void SetPackedField(int fieldNumber, ProtoWriter writer)
{
if (fieldNumber <= 0)
{
throw new ArgumentOutOfRangeException("fieldNumber");
}
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.packedFieldNumber = fieldNumber;
}
public static void ClearPackedField(int fieldNumber, ProtoWriter writer)
{
if (fieldNumber != writer.packedFieldNumber)
{
throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber + " but received " + fieldNumber);
}
writer.packedFieldNumber = 0;
}
public static void WritePackedPrefix(int elementCount, WireType wireType, ProtoWriter writer)
{
if (writer.WireType != WireType.String)
{
throw new InvalidOperationException("Invalid wire-type: " + writer.WireType);
}
if (elementCount < 0)
{
throw new ArgumentOutOfRangeException("elementCount");
}
WriteUInt64Variant(wireType switch
{
WireType.Fixed32 => (ulong)((long)elementCount << 2),
WireType.Fixed64 => (ulong)((long)elementCount << 3),
_ => throw new ArgumentOutOfRangeException("wireType", "Invalid wire-type: " + wireType),
}, writer);
writer.wireType = WireType.None;
}
internal string SerializeType(Type type)
{
return TypeModel.SerializeType(model, type);
}
public void SetRootObject(object value)
{
NetCache.SetKeyedObject(0, value);
}
public static void WriteType(Type value, ProtoWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
WriteString(writer.SerializeType(value), writer);
}
}