|
|
|
@ -67,8 +67,8 @@ namespace Google.Protobuf |
|
|
|
|
|
|
|
|
|
private readonly bool leaveOpen; |
|
|
|
|
private readonly byte[] buffer; |
|
|
|
|
private readonly int limit; |
|
|
|
|
private int position; |
|
|
|
|
private WriterInternalState state; |
|
|
|
|
|
|
|
|
|
private readonly Stream output; |
|
|
|
|
|
|
|
|
|
#region Construction |
|
|
|
@ -90,8 +90,9 @@ namespace Google.Protobuf |
|
|
|
|
{ |
|
|
|
|
this.output = null; |
|
|
|
|
this.buffer = ProtoPreconditions.CheckNotNull(buffer, nameof(buffer)); |
|
|
|
|
this.position = offset; |
|
|
|
|
this.limit = offset + length; |
|
|
|
|
this.state.position = offset; |
|
|
|
|
this.state.limit = offset + length; |
|
|
|
|
WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); |
|
|
|
|
leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -99,8 +100,9 @@ namespace Google.Protobuf |
|
|
|
|
{ |
|
|
|
|
this.output = ProtoPreconditions.CheckNotNull(output, nameof(output)); |
|
|
|
|
this.buffer = buffer; |
|
|
|
|
this.position = 0; |
|
|
|
|
this.limit = buffer.Length; |
|
|
|
|
this.state.position = 0; |
|
|
|
|
this.state.limit = buffer.Length; |
|
|
|
|
WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper); |
|
|
|
|
this.leaveOpen = leaveOpen; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -155,9 +157,9 @@ namespace Google.Protobuf |
|
|
|
|
{ |
|
|
|
|
if (output != null) |
|
|
|
|
{ |
|
|
|
|
return output.Position + position; |
|
|
|
|
return output.Position + state.position; |
|
|
|
|
} |
|
|
|
|
return position; |
|
|
|
|
return state.position; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -169,7 +171,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteDouble(double value) |
|
|
|
|
{ |
|
|
|
|
WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value)); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteDouble(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -178,23 +181,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteFloat(float value) |
|
|
|
|
{ |
|
|
|
|
byte[] rawBytes = BitConverter.GetBytes(value); |
|
|
|
|
if (!BitConverter.IsLittleEndian) |
|
|
|
|
{ |
|
|
|
|
ByteArray.Reverse(rawBytes); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (limit - position >= 4) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = rawBytes[0]; |
|
|
|
|
buffer[position++] = rawBytes[1]; |
|
|
|
|
buffer[position++] = rawBytes[2]; |
|
|
|
|
buffer[position++] = rawBytes[3]; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
WriteRawBytes(rawBytes, 0, 4); |
|
|
|
|
} |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteFloat(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -203,7 +191,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteUInt64(ulong value) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint64(value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteUInt64(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -212,7 +201,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteInt64(long value) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint64((ulong) value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteInt64(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -221,15 +211,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteInt32(int value) |
|
|
|
|
{ |
|
|
|
|
if (value >= 0) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32((uint) value); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// Must sign-extend. |
|
|
|
|
WriteRawVarint64((ulong) value); |
|
|
|
|
} |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteInt32(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -238,7 +221,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteFixed64(ulong value) |
|
|
|
|
{ |
|
|
|
|
WriteRawLittleEndian64(value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteFixed64(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -247,7 +231,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteFixed32(uint value) |
|
|
|
|
{ |
|
|
|
|
WriteRawLittleEndian32(value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteFixed32(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -256,7 +241,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteBool(bool value) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(value ? (byte) 1 : (byte) 0); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteBool(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -266,30 +252,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteString(string value) |
|
|
|
|
{ |
|
|
|
|
// Optimise the case where we have enough space to write |
|
|
|
|
// the string directly to the buffer, which should be common. |
|
|
|
|
int length = Utf8Encoding.GetByteCount(value); |
|
|
|
|
WriteLength(length); |
|
|
|
|
if (limit - position >= length) |
|
|
|
|
{ |
|
|
|
|
if (length == value.Length) // Must be all ASCII... |
|
|
|
|
{ |
|
|
|
|
for (int i = 0; i < length; i++) |
|
|
|
|
{ |
|
|
|
|
buffer[position + i] = (byte)value[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position); |
|
|
|
|
} |
|
|
|
|
position += length; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
byte[] bytes = Utf8Encoding.GetBytes(value); |
|
|
|
|
WriteRawBytes(bytes); |
|
|
|
|
} |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteString(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -299,6 +263,7 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteMessage(IMessage value) |
|
|
|
|
{ |
|
|
|
|
// TOOD: implement.... |
|
|
|
|
WriteLength(value.CalculateSize()); |
|
|
|
|
value.WriteTo(this); |
|
|
|
|
} |
|
|
|
@ -309,6 +274,7 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteGroup(IMessage value) |
|
|
|
|
{ |
|
|
|
|
// TODO: implement... |
|
|
|
|
value.WriteTo(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -319,8 +285,9 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteBytes(ByteString value) |
|
|
|
|
{ |
|
|
|
|
WriteLength(value.Length); |
|
|
|
|
value.WriteRawBytesTo(this); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteLength(ref span, ref state, value.Length); |
|
|
|
|
WritingPrimitives.WriteBytes(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -329,7 +296,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteUInt32(uint value) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32(value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteUInt32(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -338,7 +306,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteEnum(int value) |
|
|
|
|
{ |
|
|
|
|
WriteInt32(value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteEnum(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -347,7 +316,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write.</param> |
|
|
|
|
public void WriteSFixed32(int value) |
|
|
|
|
{ |
|
|
|
|
WriteRawLittleEndian32((uint) value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteSFixed32(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -356,7 +326,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteSFixed64(long value) |
|
|
|
|
{ |
|
|
|
|
WriteRawLittleEndian64((ulong) value); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteSFixed64(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -365,7 +336,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteSInt32(int value) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32(EncodeZigZag32(value)); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteSInt32(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -374,7 +346,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="value">The value to write</param> |
|
|
|
|
public void WriteSInt64(long value) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint64(EncodeZigZag64(value)); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteSInt64(ref span, ref state, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -386,7 +359,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="length">Length value, in bytes.</param> |
|
|
|
|
public void WriteLength(int length) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32((uint) length); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteLength(ref span, ref state, length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endregion |
|
|
|
@ -399,7 +373,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="type">The wire format type of the tag to write</param> |
|
|
|
|
public void WriteTag(int fieldNumber, WireFormat.WireType type) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type)); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -408,7 +383,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="tag">The encoded tag</param> |
|
|
|
|
public void WriteTag(uint tag) |
|
|
|
|
{ |
|
|
|
|
WriteRawVarint32(tag); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteTag(ref span, ref state, tag); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -417,7 +393,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="b1">The encoded tag</param> |
|
|
|
|
public void WriteRawTag(byte b1) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(b1); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawTag(ref span, ref state, b1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -427,8 +404,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="b2">The second byte of the encoded tag</param> |
|
|
|
|
public void WriteRawTag(byte b1, byte b2) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(b1); |
|
|
|
|
WriteRawByte(b2); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -439,9 +416,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="b3">The third byte of the encoded tag</param> |
|
|
|
|
public void WriteRawTag(byte b1, byte b2, byte b3) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(b1); |
|
|
|
|
WriteRawByte(b2); |
|
|
|
|
WriteRawByte(b3); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -453,10 +429,8 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="b4">The fourth byte of the encoded tag</param> |
|
|
|
|
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(b1); |
|
|
|
|
WriteRawByte(b2); |
|
|
|
|
WriteRawByte(b3); |
|
|
|
|
WriteRawByte(b4); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -469,130 +443,128 @@ namespace Google.Protobuf |
|
|
|
|
/// <param name="b5">The fifth byte of the encoded tag</param> |
|
|
|
|
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte(b1); |
|
|
|
|
WriteRawByte(b2); |
|
|
|
|
WriteRawByte(b3); |
|
|
|
|
WriteRawByte(b4); |
|
|
|
|
WriteRawByte(b5); |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5); |
|
|
|
|
} |
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
#region Underlying writing primitives |
|
|
|
|
/// <summary> |
|
|
|
|
/// Writes a 32 bit value as a varint. The fast route is taken when |
|
|
|
|
/// there's enough buffer space left to whizz through without checking |
|
|
|
|
/// for each byte; otherwise, we resort to calling WriteRawByte each time. |
|
|
|
|
/// </summary> |
|
|
|
|
internal void WriteRawVarint32(uint value) |
|
|
|
|
{ |
|
|
|
|
// Optimize for the common case of a single byte value |
|
|
|
|
if (value < 128 && position < limit) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = (byte)value; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (value > 127 && position < limit) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
|
|
|
|
value >>= 7; |
|
|
|
|
} |
|
|
|
|
while (value > 127) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) ((value & 0x7F) | 0x80)); |
|
|
|
|
value >>= 7; |
|
|
|
|
} |
|
|
|
|
if (position < limit) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = (byte) value; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) value); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal void WriteRawVarint64(ulong value) |
|
|
|
|
{ |
|
|
|
|
while (value > 127 && position < limit) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
|
|
|
|
value >>= 7; |
|
|
|
|
} |
|
|
|
|
while (value > 127) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) ((value & 0x7F) | 0x80)); |
|
|
|
|
value >>= 7; |
|
|
|
|
} |
|
|
|
|
if (position < limit) |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = (byte) value; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) value); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal void WriteRawLittleEndian32(uint value) |
|
|
|
|
{ |
|
|
|
|
if (position + 4 > limit) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) value); |
|
|
|
|
WriteRawByte((byte) (value >> 8)); |
|
|
|
|
WriteRawByte((byte) (value >> 16)); |
|
|
|
|
WriteRawByte((byte) (value >> 24)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = ((byte) value); |
|
|
|
|
buffer[position++] = ((byte) (value >> 8)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 16)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 24)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal void WriteRawLittleEndian64(ulong value) |
|
|
|
|
{ |
|
|
|
|
if (position + 8 > limit) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) value); |
|
|
|
|
WriteRawByte((byte) (value >> 8)); |
|
|
|
|
WriteRawByte((byte) (value >> 16)); |
|
|
|
|
WriteRawByte((byte) (value >> 24)); |
|
|
|
|
WriteRawByte((byte) (value >> 32)); |
|
|
|
|
WriteRawByte((byte) (value >> 40)); |
|
|
|
|
WriteRawByte((byte) (value >> 48)); |
|
|
|
|
WriteRawByte((byte) (value >> 56)); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
buffer[position++] = ((byte) value); |
|
|
|
|
buffer[position++] = ((byte) (value >> 8)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 16)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 24)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 32)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 40)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 48)); |
|
|
|
|
buffer[position++] = ((byte) (value >> 56)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal void WriteRawByte(byte value) |
|
|
|
|
{ |
|
|
|
|
if (position == limit) |
|
|
|
|
{ |
|
|
|
|
RefreshBuffer(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
buffer[position++] = value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
internal void WriteRawByte(uint value) |
|
|
|
|
{ |
|
|
|
|
WriteRawByte((byte) value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//#region Underlying writing primitives |
|
|
|
|
///// <summary> |
|
|
|
|
///// Writes a 32 bit value as a varint. The fast route is taken when |
|
|
|
|
///// there's enough buffer space left to whizz through without checking |
|
|
|
|
///// for each byte; otherwise, we resort to calling WriteRawByte each time. |
|
|
|
|
///// </summary> |
|
|
|
|
//internal void WriteRawVarint32(uint value) |
|
|
|
|
//{ |
|
|
|
|
// // Optimize for the common case of a single byte value |
|
|
|
|
// if (value < 128 && position < limit) |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = (byte)value; |
|
|
|
|
// return; |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
// while (value > 127 && position < limit) |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
|
|
|
|
// value >>= 7; |
|
|
|
|
// } |
|
|
|
|
// while (value > 127) |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) ((value & 0x7F) | 0x80)); |
|
|
|
|
// value >>= 7; |
|
|
|
|
// } |
|
|
|
|
// if (position < limit) |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = (byte) value; |
|
|
|
|
// } |
|
|
|
|
// else |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) value); |
|
|
|
|
// } |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//internal void WriteRawVarint64(ulong value) |
|
|
|
|
//{ |
|
|
|
|
// while (value > 127 && position < limit) |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
|
|
|
|
// value >>= 7; |
|
|
|
|
// } |
|
|
|
|
// while (value > 127) |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) ((value & 0x7F) | 0x80)); |
|
|
|
|
// value >>= 7; |
|
|
|
|
// } |
|
|
|
|
// if (position < limit) |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = (byte) value; |
|
|
|
|
// } |
|
|
|
|
// else |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) value); |
|
|
|
|
// } |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//internal void WriteRawLittleEndian32(uint value) |
|
|
|
|
//{ |
|
|
|
|
// if (position + 4 > limit) |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) value); |
|
|
|
|
// WriteRawByte((byte) (value >> 8)); |
|
|
|
|
// WriteRawByte((byte) (value >> 16)); |
|
|
|
|
// WriteRawByte((byte) (value >> 24)); |
|
|
|
|
// } |
|
|
|
|
// else |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = ((byte) value); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 8)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 16)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 24)); |
|
|
|
|
// } |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//internal void WriteRawLittleEndian64(ulong value) |
|
|
|
|
//{ |
|
|
|
|
// if (position + 8 > limit) |
|
|
|
|
// { |
|
|
|
|
// WriteRawByte((byte) value); |
|
|
|
|
// WriteRawByte((byte) (value >> 8)); |
|
|
|
|
// WriteRawByte((byte) (value >> 16)); |
|
|
|
|
// WriteRawByte((byte) (value >> 24)); |
|
|
|
|
// WriteRawByte((byte) (value >> 32)); |
|
|
|
|
// WriteRawByte((byte) (value >> 40)); |
|
|
|
|
// WriteRawByte((byte) (value >> 48)); |
|
|
|
|
// WriteRawByte((byte) (value >> 56)); |
|
|
|
|
// } |
|
|
|
|
// else |
|
|
|
|
// { |
|
|
|
|
// buffer[position++] = ((byte) value); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 8)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 16)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 24)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 32)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 40)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 48)); |
|
|
|
|
// buffer[position++] = ((byte) (value >> 56)); |
|
|
|
|
// } |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//internal void WriteRawByte(byte value) |
|
|
|
|
//{ |
|
|
|
|
// if (position == limit) |
|
|
|
|
// { |
|
|
|
|
// RefreshBuffer(); |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
// buffer[position++] = value; |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//internal void WriteRawByte(uint value) |
|
|
|
|
//{ |
|
|
|
|
// WriteRawByte((byte) value); |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
// TODO: get rid of this internal method |
|
|
|
|
/// <summary> |
|
|
|
|
/// Writes out an array of bytes. |
|
|
|
|
/// </summary> |
|
|
|
@ -601,89 +573,60 @@ namespace Google.Protobuf |
|
|
|
|
WriteRawBytes(value, 0, value.Length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: get rid of this internal method |
|
|
|
|
/// <summary> |
|
|
|
|
/// Writes out part of an array of bytes. |
|
|
|
|
/// </summary> |
|
|
|
|
internal void WriteRawBytes(byte[] value, int offset, int length) |
|
|
|
|
{ |
|
|
|
|
if (limit - position >= length) |
|
|
|
|
{ |
|
|
|
|
ByteArray.Copy(value, offset, buffer, position, length); |
|
|
|
|
// We have room in the current buffer. |
|
|
|
|
position += length; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// Write extends past current buffer. Fill the rest of this buffer and |
|
|
|
|
// flush. |
|
|
|
|
int bytesWritten = limit - position; |
|
|
|
|
ByteArray.Copy(value, offset, buffer, position, bytesWritten); |
|
|
|
|
offset += bytesWritten; |
|
|
|
|
length -= bytesWritten; |
|
|
|
|
position = limit; |
|
|
|
|
RefreshBuffer(); |
|
|
|
|
|
|
|
|
|
// Now deal with the rest. |
|
|
|
|
// Since we have an output stream, this is our buffer |
|
|
|
|
// and buffer offset == 0 |
|
|
|
|
if (length <= limit) |
|
|
|
|
{ |
|
|
|
|
// Fits in new buffer. |
|
|
|
|
ByteArray.Copy(value, offset, buffer, 0, length); |
|
|
|
|
position = length; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// Write is very big. Let's do it all at once. |
|
|
|
|
output.Write(value, offset, length); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Encode a 32-bit value with ZigZag encoding. |
|
|
|
|
/// </summary> |
|
|
|
|
/// <remarks> |
|
|
|
|
/// ZigZag encodes signed integers into values that can be efficiently |
|
|
|
|
/// encoded with varint. (Otherwise, negative values must be |
|
|
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking |
|
|
|
|
/// 10 bytes on the wire.) |
|
|
|
|
/// </remarks> |
|
|
|
|
internal static uint EncodeZigZag32(int n) |
|
|
|
|
{ |
|
|
|
|
// Note: the right-shift must be arithmetic |
|
|
|
|
return (uint) ((n << 1) ^ (n >> 31)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Encode a 64-bit value with ZigZag encoding. |
|
|
|
|
/// </summary> |
|
|
|
|
/// <remarks> |
|
|
|
|
/// ZigZag encodes signed integers into values that can be efficiently |
|
|
|
|
/// encoded with varint. (Otherwise, negative values must be |
|
|
|
|
/// sign-extended to 64 bits to be varint encoded, thus always taking |
|
|
|
|
/// 10 bytes on the wire.) |
|
|
|
|
/// </remarks> |
|
|
|
|
internal static ulong EncodeZigZag64(long n) |
|
|
|
|
{ |
|
|
|
|
return (ulong) ((n << 1) ^ (n >> 63)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void RefreshBuffer() |
|
|
|
|
{ |
|
|
|
|
if (output == null) |
|
|
|
|
{ |
|
|
|
|
// We're writing to a single buffer. |
|
|
|
|
throw new OutOfSpaceException(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Since we have an output stream, this is our buffer |
|
|
|
|
// and buffer offset == 0 |
|
|
|
|
output.Write(buffer, 0, position); |
|
|
|
|
position = 0; |
|
|
|
|
} |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//#endregion |
|
|
|
|
|
|
|
|
|
///// <summary> |
|
|
|
|
///// Encode a 32-bit value with ZigZag encoding. |
|
|
|
|
///// </summary> |
|
|
|
|
///// <remarks> |
|
|
|
|
///// ZigZag encodes signed integers into values that can be efficiently |
|
|
|
|
///// encoded with varint. (Otherwise, negative values must be |
|
|
|
|
///// sign-extended to 64 bits to be varint encoded, thus always taking |
|
|
|
|
///// 10 bytes on the wire.) |
|
|
|
|
///// </remarks> |
|
|
|
|
//internal static uint EncodeZigZag32(int n) |
|
|
|
|
//{ |
|
|
|
|
// // Note: the right-shift must be arithmetic |
|
|
|
|
// return (uint) ((n << 1) ^ (n >> 31)); |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
///// <summary> |
|
|
|
|
///// Encode a 64-bit value with ZigZag encoding. |
|
|
|
|
///// </summary> |
|
|
|
|
///// <remarks> |
|
|
|
|
///// ZigZag encodes signed integers into values that can be efficiently |
|
|
|
|
///// encoded with varint. (Otherwise, negative values must be |
|
|
|
|
///// sign-extended to 64 bits to be varint encoded, thus always taking |
|
|
|
|
///// 10 bytes on the wire.) |
|
|
|
|
///// </remarks> |
|
|
|
|
//internal static ulong EncodeZigZag64(long n) |
|
|
|
|
//{ |
|
|
|
|
// return (ulong) ((n << 1) ^ (n >> 63)); |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
//private void RefreshBuffer() |
|
|
|
|
//{ |
|
|
|
|
// if (output == null) |
|
|
|
|
// { |
|
|
|
|
// // We're writing to a single buffer. |
|
|
|
|
// throw new OutOfSpaceException(); |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
// // Since we have an output stream, this is our buffer |
|
|
|
|
// // and buffer offset == 0 |
|
|
|
|
// output.Write(buffer, 0, position); |
|
|
|
|
// position = 0; |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Indicates that a CodedOutputStream wrapping a flat byte array |
|
|
|
@ -726,10 +669,13 @@ namespace Google.Protobuf |
|
|
|
|
/// </summary> |
|
|
|
|
public void Flush() |
|
|
|
|
{ |
|
|
|
|
if (output != null) |
|
|
|
|
var span = new Span<byte>(buffer); |
|
|
|
|
state.writeBufferHelper.Flush(ref span, ref state); |
|
|
|
|
|
|
|
|
|
/*if (output != null) |
|
|
|
|
{ |
|
|
|
|
RefreshBuffer(); |
|
|
|
|
} |
|
|
|
|
}*/ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -756,7 +702,7 @@ namespace Google.Protobuf |
|
|
|
|
{ |
|
|
|
|
if (output == null) |
|
|
|
|
{ |
|
|
|
|
return limit - position; |
|
|
|
|
return state.limit - state.position; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
@ -770,5 +716,7 @@ namespace Google.Protobuf |
|
|
|
|
internal byte[] InternalBuffer => buffer; |
|
|
|
|
|
|
|
|
|
internal Stream InternalOutputStream => output; |
|
|
|
|
|
|
|
|
|
internal ref WriterInternalState InternalState => ref state; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|