From 9df2defa295e1a3b315ed2a88791db51ff1f53e7 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Tue, 4 Aug 2015 11:26:48 +0100 Subject: Consume unknown fields when parsing. This is expected to be the cause of the conformance test failures. Generated code in next commit. --- .../Google.Protobuf.Test/GeneratedMessageTest.cs | 29 +++++++++++++++++++ csharp/src/Google.Protobuf/CodedInputStream.cs | 33 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'csharp') diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs index 2b6265c1..1ef3d753 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs @@ -36,6 +36,8 @@ using Google.Protobuf.TestProtos; using NUnit.Framework; using System.Collections; using System.Collections.Generic; +using System.Linq; +using Google.Protobuf.WellKnownTypes; namespace Google.Protobuf { @@ -590,5 +592,32 @@ namespace Google.Protobuf Assert.AreEqual(message, message2); Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); } + + [Test] + public void IgnoreUnknownFields_RealDataStillRead() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var stream = new MemoryStream(); + var output = new CodedOutputStream(stream); + var unusedFieldNumber = 23456; + Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); + output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); + output.WriteString("ignore me"); + message.WriteTo(output); + output.Flush(); + + stream.Position = 0; + var parsed = TestAllTypes.Parser.ParseFrom(stream); + Assert.AreEqual(message, parsed); + } + + [Test] + public void IgnoreUnknownFields_AllTypes() + { + // Simple way of ensuring we can skip all kinds of fields. + var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); + var empty = Empty.Parser.ParseFrom(data); + Assert.AreEqual(new Empty(), empty); + } } } diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs index a1abfcb0..fee31e3b 100644 --- a/csharp/src/Google.Protobuf/CodedInputStream.cs +++ b/csharp/src/Google.Protobuf/CodedInputStream.cs @@ -308,6 +308,39 @@ namespace Google.Protobuf return true; } + /// + /// Consumes the data for the field with the tag we've just read. + /// This should be called directly after , when + /// the caller wishes to skip an unknown field. + /// + public void ConsumeLastField() + { + if (lastTag == 0) + { + throw new InvalidOperationException("ConsumeLastField cannot be called at the end of a stream"); + } + switch (WireFormat.GetTagWireType(lastTag)) + { + case WireFormat.WireType.StartGroup: + case WireFormat.WireType.EndGroup: + // TODO: Work out how to skip them instead? See issue 688. + throw new InvalidProtocolBufferException("Group tags not supported by proto3 C# implementation"); + case WireFormat.WireType.Fixed32: + ReadFixed32(); + break; + case WireFormat.WireType.Fixed64: + ReadFixed64(); + break; + case WireFormat.WireType.LengthDelimited: + var length = ReadLength(); + SkipRawBytes(length); + break; + case WireFormat.WireType.Varint: + ReadRawVarint32(); + break; + } + } + /// /// Reads a double field from the stream. /// -- cgit v1.2.3