Ejemplo n.º 1
0
        public void LegacyGeneratedCodeThrowsWithReadOnlySequence()
        {
            var message = new ParseContextEnabledMessageB
            {
                A = new LegacyGeneratedCodeMessageA
                {
                    Bb = new ParseContextEnabledMessageB {
                        OptionalInt32 = 12345
                    }
                },
                OptionalInt32 = 6789
            };
            var data = message.ToByteArray();

            // if parsing started using ReadOnlySequence and we don't have a CodedInputStream
            // instance at hand, we cannot fall back to the legacy MergeFrom(CodedInputStream)
            // method and parsing will fail. As a consequence, one can only use parsing
            // from ReadOnlySequence if all the messages in the parsing tree have their generated
            // code up to date.
            var exception = Assert.Throws <InvalidProtocolBufferException>(() =>
            {
                ParseContext.Initialize(new ReadOnlySequence <byte>(data), out ParseContext parseCtx);
                var parsed = new ParseContextEnabledMessageB();
                ParsingPrimitivesMessages.ReadRawMessage(ref parseCtx, parsed);
            });

            Assert.AreEqual($"Message {typeof(LegacyGeneratedCodeMessageA).Name} doesn't provide the generated method that enables ParseContext-based parsing. You might need to regenerate the generated protobuf code.", exception.Message);
        }
Ejemplo n.º 2
0
 internal static void MergeFrom(this IMessage message, ReadOnlySpan <byte> data, bool discardUnknownFields, ExtensionRegistry registry)
 {
     ParseContext.Initialize(data, out ParseContext ctx);
     ctx.DiscardUnknownFields = discardUnknownFields;
     ctx.ExtensionRegistry    = registry;
     ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
     ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref ctx.state);
 }
Ejemplo n.º 3
0
 private static void AssertReadFromParseContext(ReadOnlySequence <byte> input, ParseContextAssertAction assertAction, bool assertIsAtEnd)
 {
     ParseContext.Initialize(input, out ParseContext parseCtx);
     assertAction(ref parseCtx);
     if (assertIsAtEnd)
     {
         Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state));
     }
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Reads a top-level message or a nested message after the limits for this message have been pushed.
 /// (parser will proceed until the end of the current limit)
 /// NOTE: this method needs to be public because it's invoked by the generated code - e.g. msg.MergeFrom(CodedInputStream input) method
 /// </summary>
 public void ReadRawMessage(IMessage message)
 {
     ParseContext.Initialize(this, out ParseContext ctx);
     try
     {
         ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
     }
     finally
     {
         ctx.CopyStateTo(this);
     }
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Reads an embedded group field from the stream.
 /// </summary>
 public void ReadGroup(IMessage builder)
 {
     ParseContext.Initialize(this, out ParseContext ctx);
     try
     {
         ParsingPrimitivesMessages.ReadGroup(ref ctx, builder);
     }
     finally
     {
         ctx.CopyStateTo(this);
     }
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Tries to merge a field from the coded input, returning true if the field was merged.
 /// If the set is null or the field was not otherwise merged, this returns false.
 /// </summary>
 public static bool TryMergeFieldFrom <TTarget>(ref ExtensionSet <TTarget> set, CodedInputStream stream) where TTarget : IExtendableMessage <TTarget>
 {
     ParseContext.Initialize(stream, out ParseContext ctx);
     try
     {
         return(TryMergeFieldFrom <TTarget>(ref set, ref ctx));
     }
     finally
     {
         ctx.CopyStateTo(stream);
     }
 }
Ejemplo n.º 7
0
 /// <summary>
 /// Create a new UnknownFieldSet if unknownFields is null.
 /// Parse a single field from <paramref name="input"/> and merge it
 /// into unknownFields. If <paramref name="input"/> is configured to discard unknown fields,
 /// <paramref name="unknownFields"/> will be returned as-is and the field will be skipped.
 /// </summary>
 /// <param name="unknownFields">The UnknownFieldSet which need to be merged</param>
 /// <param name="input">The coded input stream containing the field</param>
 /// <returns>The merged UnknownFieldSet</returns>
 public static UnknownFieldSet MergeFieldFrom(UnknownFieldSet unknownFields,
                                              CodedInputStream input)
 {
     ParseContext.Initialize(input, out ParseContext ctx);
     try
     {
         return(MergeFieldFrom(unknownFields, ref ctx));
     }
     finally
     {
         ctx.CopyStateTo(input);
     }
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Reads an embedded message field value from the stream.
 /// </summary>
 public void ReadMessage(IMessage builder)
 {
     // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalMergeFrom method),
     // what we're doing here works fine, but could be more efficient.
     // What happens is that we first initialize a ParseContext from the current coded input stream only to parse the length of the message, at which point
     // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to
     // invoke the legacy MergeFrom(CodedInputStream) method.
     // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it).
     ParseContext.Initialize(buffer.AsSpan(), ref state, out ParseContext ctx);
     try
     {
         ParsingPrimitivesMessages.ReadMessage(ref ctx, builder);
     }
     finally
     {
         ctx.CopyStateTo(this);
     }
 }
Ejemplo n.º 9
0
        private static void AssertReadFromParseContext(ReadOnlySequence <byte> input, ParseContextAssertAction assertAction, bool assertIsAtEnd)
        {
            // Check as ReadOnlySequence<byte>
            ParseContext.Initialize(input, out ParseContext parseCtx);
            assertAction(ref parseCtx);
            if (assertIsAtEnd)
            {
                Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref parseCtx.buffer, ref parseCtx.state));
            }

            // Check as ReadOnlySpan<byte>
            ParseContext.Initialize(input.ToArray().AsSpan(), out ParseContext spanParseContext);
            assertAction(ref spanParseContext);
            if (assertIsAtEnd)
            {
                Assert.IsTrue(SegmentedBufferHelper.IsAtEnd(ref spanParseContext.buffer, ref spanParseContext.state));
            }
        }
        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));
        }