public void DecodeZigZag32() { Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(0)); Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(1)); Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(2)); Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag32(3)); Assert.AreEqual(0x3FFFFFFF, ParsingPrimitives.DecodeZigZag32(0x7FFFFFFE)); Assert.AreEqual(unchecked ((int)0xC0000000), ParsingPrimitives.DecodeZigZag32(0x7FFFFFFF)); Assert.AreEqual(0x7FFFFFFF, ParsingPrimitives.DecodeZigZag32(0xFFFFFFFE)); Assert.AreEqual(unchecked ((int)0x80000000), ParsingPrimitives.DecodeZigZag32(0xFFFFFFFF)); }
/// <summary> /// Parses the next tag. /// If the end of logical stream was reached, an invalid tag of 0 is returned. /// </summary> public static uint ParseTag(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state) { // The "nextTag" logic is there only as an optimization for reading non-packed repeated / map // fields and is strictly speaking not necessary. // TODO(jtattermusch): look into simplifying the ParseTag logic. if (state.hasNextTag) { state.lastTag = state.nextTag; state.hasNextTag = false; return(state.lastTag); } // Optimize for the incredibly common case of having at least two bytes left in the buffer, // and those two bytes being enough to get the tag. This will be true for fields up to 4095. if (state.bufferPos + 2 <= state.bufferSize) { int tmp = buffer[state.bufferPos++]; if (tmp < 128) { state.lastTag = (uint)tmp; } else { int result = tmp & 0x7f; if ((tmp = buffer[state.bufferPos++]) < 128) { result |= tmp << 7; state.lastTag = (uint)result; } else { // Nope, rewind and go the potentially slow route. state.bufferPos -= 2; state.lastTag = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); } } } else { if (SegmentedBufferHelper.IsAtEnd(ref buffer, ref state)) { state.lastTag = 0; return(0); } state.lastTag = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); } if (WireFormat.GetTagFieldNumber(state.lastTag) == 0) { // If we actually read a tag with a field of 0, that's not a valid tag. throw InvalidProtocolBufferException.InvalidTag(); } return(state.lastTag); }
public void RoundTripZigZag64() { Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); Assert.AreEqual(856912304801416L, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); Assert.AreEqual(-75123905439571256L, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); }
public void DecodeZigZag64() { Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(0)); Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(1)); Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(2)); Assert.AreEqual(-2, ParsingPrimitives.DecodeZigZag64(3)); Assert.AreEqual(0x000000003FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFEL)); Assert.AreEqual(unchecked ((long)0xFFFFFFFFC0000000L), ParsingPrimitives.DecodeZigZag64(0x000000007FFFFFFFL)); Assert.AreEqual(0x000000007FFFFFFFL, ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFEL)); Assert.AreEqual(unchecked ((long)0xFFFFFFFF80000000L), ParsingPrimitives.DecodeZigZag64(0x00000000FFFFFFFFL)); Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); Assert.AreEqual(unchecked ((long)0x8000000000000000L), ParsingPrimitives.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); }
internal static uint?ReadUInt32Wrapper(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state) { // field=1, type=varint = tag of 8 const int expectedTag = 8; // length:1 + tag:1 + value:10(varint64-max) = 12 bytes // Value can be 64 bits for negative integers if (state.bufferPos + 12 <= state.bufferSize) { // The entire wrapper message is already contained in `buffer`. int pos0 = state.bufferPos; int length = buffer[state.bufferPos++]; if (length == 0) { return(0); } // Length will always fit in a single byte. if (length >= 128) { state.bufferPos = pos0; return(ReadUInt32WrapperSlow(ref buffer, ref state)); } int finalBufferPos = state.bufferPos + length; if (buffer[state.bufferPos++] != expectedTag) { state.bufferPos = pos0; return(ReadUInt32WrapperSlow(ref buffer, ref state)); } var result = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); // Verify this message only contained a single field. if (state.bufferPos != finalBufferPos) { state.bufferPos = pos0; return(ReadUInt32WrapperSlow(ref buffer, ref state)); } return(result); } else { return(ReadUInt32WrapperSlow(ref buffer, ref state)); } }
public static void ReadMessage(ref ParseContext ctx, IMessage message) { int length = ParsingPrimitives.ParseLength(ref ctx.buffer, ref ctx.state); if (ctx.state.recursionDepth >= ctx.state.recursionLimit) { throw InvalidProtocolBufferException.RecursionLimitExceeded(); } int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); ++ctx.state.recursionDepth; ReadRawMessage(ref ctx, message); CheckReadEndOfStreamTag(ref ctx.state); // Check that we've read exactly as much data as expected. if (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) { throw InvalidProtocolBufferException.TruncatedMessage(); } --ctx.state.recursionDepth; SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); }
/// <summary> /// Skip a group. /// </summary> public static void SkipGroup(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state, uint startGroupTag) { // Note: Currently we expect this to be the way that groups are read. We could put the recursion // depth changes into the ReadTag method instead, potentially... state.recursionDepth++; if (state.recursionDepth >= state.recursionLimit) { throw InvalidProtocolBufferException.RecursionLimitExceeded(); } uint tag; while (true) { tag = ParsingPrimitives.ParseTag(ref buffer, ref state); if (tag == 0) { throw InvalidProtocolBufferException.TruncatedMessage(); } // Can't call SkipLastField for this case- that would throw. if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup) { break; } // This recursion will allow us to handle nested groups. SkipLastField(ref buffer, ref state); } int startField = WireFormat.GetTagFieldNumber(startGroupTag); int endField = WireFormat.GetTagFieldNumber(tag); if (startField != endField) { throw new InvalidProtocolBufferException( $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}"); } state.recursionDepth--; }
/// <summary> /// Reads an sint32 field value from the stream. /// </summary> public int ReadSInt32() { return(ParsingPrimitives.DecodeZigZag32(ReadRawVarint32())); }
/// <summary> /// Reads a bytes field value from the stream. /// </summary> public ByteString ReadBytes() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ReadBytes(ref span, ref state)); }
/// <summary> /// Reads a float field from the stream. /// </summary> public float ReadFloat() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseFloat(ref span, ref state)); }
public uint ReadUInt32() { return(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); }
public int ReadSFixed32() { return((int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state)); }
/// <summary> /// Reads a varint from the input one byte at a time, so that it does not /// read any bytes after the end of the varint. If you simply wrapped the /// stream in a CodedInputStream and used ReadRawVarint32(Stream) /// then you would probably end up reading past the end of the varint since /// CodedInputStream buffers its input. /// </summary> /// <param name="input"></param> /// <returns></returns> internal static uint ReadRawVarint32(Stream input) { return(ParsingPrimitives.ReadRawVarint32(input)); }
/// <summary> /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>, /// the tag is consumed and the method returns <c>true</c>; otherwise, the /// stream is left in the original position and the method returns <c>false</c>. /// </summary> public bool MaybeConsumeTag(uint tag) { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.MaybeConsumeTag(ref span, ref state, tag)); }
public static KeyValuePair <TKey, TValue> ReadMapEntry <TKey, TValue>(ref ParseContext ctx, MapField <TKey, TValue> .Codec codec) { int length = ParsingPrimitives.ParseLength(ref ctx.buffer, ref ctx.state); if (ctx.state.recursionDepth >= ctx.state.recursionLimit) { throw InvalidProtocolBufferException.RecursionLimitExceeded(); } int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); ++ctx.state.recursionDepth; TKey key = codec.KeyCodec.DefaultValue; TValue value = codec.ValueCodec.DefaultValue; uint tag; while ((tag = ctx.ReadTag()) != 0) { if (tag == codec.KeyCodec.Tag) { key = codec.KeyCodec.Read(ref ctx); } else if (tag == codec.ValueCodec.Tag) { value = codec.ValueCodec.Read(ref ctx); } else { SkipLastField(ref ctx.buffer, ref ctx.state); } } // Corner case: a map entry with a key but no value, where the value type is a message. // Read it as if we'd seen input with no data (i.e. create a "default" message). if (value == null) { if (ctx.state.CodedInputStream != null) { // the decoded message might not support parsing from ParseContext, so // we need to allow fallback to the legacy MergeFrom(CodedInputStream) parsing. value = codec.ValueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData)); } else { ParseContext.Initialize(new ReadOnlySequence <byte>(ZeroLengthMessageStreamData), out ParseContext zeroLengthCtx); value = codec.ValueCodec.Read(ref zeroLengthCtx); } } CheckReadEndOfStreamTag(ref ctx.state); // Check that we've read exactly as much data as expected. if (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state)) { throw InvalidProtocolBufferException.TruncatedMessage(); } --ctx.state.recursionDepth; SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); return(new KeyValuePair <TKey, TValue>(key, value)); }
public int ReadLength() { return((int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); }
public long ReadSInt64() { return(ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state))); }
public int ReadSInt32() { return(ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state))); }
public long ReadSFixed64() { return((long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state)); }
/// <summary> /// Reads an sint64 field value from the stream. /// </summary> public long ReadSInt64() { return(ParsingPrimitives.DecodeZigZag64(ReadRawVarint64())); }
/// <summary> /// Reads a length for length-delimited data. /// </summary> /// <remarks> /// This is internally just reading a varint, but this method exists /// to make the calling code clearer. /// </remarks> public int ReadLength() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseLength(ref span, ref state)); }
/// <summary> /// Reads a fixed size of bytes from the input. /// </summary> /// <exception cref="InvalidProtocolBufferException"> /// the end of the stream or the current limit was reached /// </exception> internal byte[] ReadRawBytes(int size) { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ReadRawBytes(ref span, ref state, size)); }
/// <summary> /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits. /// This method is optimised for the case where we've got lots of data in the buffer. /// That means we can check the size just once, then just read directly from the buffer /// without constant rechecking of the buffer length. /// </summary> internal uint ReadRawVarint32() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseRawVarint32(ref span, ref state)); }
public static ByteString ReadBytes(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state) { int length = ParsingPrimitives.ParseLength(ref buffer, ref state); return(ByteString.AttachBytes(ParsingPrimitives.ReadRawBytes(ref buffer, ref state, length))); }
/// <summary> /// Reads a 64-bit little-endian integer from the stream. /// </summary> internal ulong ReadRawLittleEndian64() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseRawLittleEndian64(ref span, ref state)); }
public int ReadEnum() { // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. return((int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); }
public static string ReadString(ref ReadOnlySpan <byte> buffer, ref ParserInternalState state) { int length = ParsingPrimitives.ParseLength(ref buffer, ref state); return(ParsingPrimitives.ReadRawString(ref buffer, ref state, length)); }
/// <summary> /// Reads a double field from the stream. /// </summary> public double ReadDouble() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseDouble(ref span, ref state)); }
/// <summary> /// Reads a field tag, returning the tag of 0 for "end of stream". /// </summary> /// <remarks> /// If this method returns 0, it doesn't necessarily mean the end of all /// the data in this CodedInputStream; it may be the end of the logical stream /// for an embedded message, for example. /// </remarks> /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns> public uint ReadTag() { var span = new ReadOnlySpan <byte>(buffer); return(ParsingPrimitives.ParseTag(ref span, ref state)); }
public ByteString ReadBytes() { return(ParsingPrimitives.ReadBytes(ref buffer, ref state)); }