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); }
/// <summary> /// Discards the current limit, returning the previous limit. /// </summary> internal void PopLimit(int oldLimit) { SegmentedBufferHelper.PopLimit(ref state, oldLimit); }
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)); }