/// <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); }
internal static void Initialize(ReadOnlySequence <byte> input, int recursionLimit, out ParseContext ctx) { ctx.buffer = default; ctx.state = default; ctx.state.lastTag = 0; ctx.state.recursionDepth = 0; ctx.state.sizeLimit = DefaultSizeLimit; ctx.state.recursionLimit = recursionLimit; ctx.state.currentLimit = int.MaxValue; SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer); ctx.state.bufferPos = 0; ctx.state.bufferSize = ctx.buffer.Length; ctx.state.DiscardUnknownFields = false; ctx.state.ExtensionRegistry = null; }
public static void Initialize(ReadOnlySequence <byte> sequence, out SegmentedBufferHelper instance, out ReadOnlySpan <byte> firstSpan) { instance.codedInputStream = null; if (sequence.IsSingleSegment) { firstSpan = sequence.First.Span; instance.totalLength = firstSpan.Length; instance.readOnlySequenceEnumerator = default; } else { instance.readOnlySequenceEnumerator = sequence.GetEnumerator(); instance.totalLength = (int)sequence.Length; // set firstSpan to the first segment instance.readOnlySequenceEnumerator.MoveNext(); firstSpan = instance.readOnlySequenceEnumerator.Current.Span; } }
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); }
internal static T Read <T>(ref ParseContext ctx, FieldCodec <T> codec) { int length = ctx.ReadLength(); int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); uint tag; T value = codec.DefaultValue; while ((tag = ctx.ReadTag()) != 0) { if (tag == codec.Tag) { value = codec.Read(ref ctx); } else { ParsingPrimitivesMessages.SkipLastField(ref ctx.buffer, ref ctx.state); } } ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref ctx.state); SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); return(value); }
public static void Initialize(CodedInputStream codedInputStream, out SegmentedBufferHelper instance) { instance.totalLength = codedInputStream.InternalInputStream == null ? (int?)codedInputStream.InternalBuffer.Length : null; instance.readOnlySequenceEnumerator = default; instance.codedInputStream = codedInputStream; }