aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--csharp/src/AddressBook/Addressbook.cs15
-rw-r--r--csharp/src/Google.Protobuf.Conformance/Conformance.cs25
-rw-r--r--csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs88
-rw-r--r--csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs22
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs35
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs5
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs5
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs50
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs175
-rw-r--r--csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs20
-rw-r--r--csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs23
-rw-r--r--csharp/src/Google.Protobuf/ByteString.cs3
-rw-r--r--csharp/src/Google.Protobuf/CodedInputStream.cs80
-rw-r--r--csharp/src/Google.Protobuf/CodedOutputStream.cs22
-rw-r--r--csharp/src/Google.Protobuf/Collections/MapField.cs5
-rw-r--r--csharp/src/Google.Protobuf/Collections/RepeatedField.cs6
-rw-r--r--csharp/src/Google.Protobuf/FieldCodec.cs7
-rw-r--r--csharp/src/Google.Protobuf/FrameworkPortability.cs3
-rw-r--r--csharp/src/Google.Protobuf/IMessage.cs2
-rw-r--r--csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs6
-rw-r--r--csharp/src/Google.Protobuf/JsonFormatter.cs3
-rw-r--r--csharp/src/Google.Protobuf/MessageExtensions.cs6
-rw-r--r--csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs110
-rw-r--r--csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs10
-rw-r--r--csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs34
-rw-r--r--csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs8
-rw-r--r--csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs4
-rw-r--r--csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs12
-rw-r--r--csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs24
-rw-r--r--csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs4
-rw-r--r--csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs12
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Any.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Api.cs10
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs15
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs5
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Type.cs25
-rw-r--r--csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs45
-rw-r--r--csharp/src/Google.Protobuf/WireFormat.cs23
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message.cc5
43 files changed, 386 insertions, 591 deletions
diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs
index 85fa2977..f2be5bae 100644
--- a/csharp/src/AddressBook/Addressbook.cs
+++ b/csharp/src/AddressBook/Addressbook.cs
@@ -189,10 +189,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -335,10 +332,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Number = input.ReadString();
@@ -441,10 +435,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
people_.AddEntriesFrom(input, _repeated_people_codec);
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
index 50a6756c..e905d4e4 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
@@ -321,10 +321,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
ProtobufPayload = input.ReadBytes();
@@ -557,10 +554,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
ParseError = input.ReadString();
@@ -1829,10 +1823,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
OptionalInt32 = input.ReadInt32();
@@ -2256,10 +2247,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
A = input.ReadInt32();
@@ -2373,10 +2361,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
C = input.ReadInt32();
diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
index c4c92efd..c8326d80 100644
--- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
@@ -281,7 +281,6 @@ namespace Google.Protobuf
CodedInputStream input = new CodedInputStream(ms);
Assert.AreEqual(tag, input.ReadTag());
- // TODO(jonskeet): Should this be ArgumentNullException instead?
Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
}
@@ -442,5 +441,92 @@ namespace Google.Protobuf
var input = new CodedInputStream(new byte[] { 0 });
Assert.Throws<InvalidProtocolBufferException>(() => input.ReadTag());
}
+
+ [Test]
+ public void SkipGroup()
+ {
+ // Create an output stream with a group in:
+ // Field 1: string "field 1"
+ // Field 2: group containing:
+ // Field 1: fixed int32 value 100
+ // Field 2: string "ignore me"
+ // Field 3: nested group containing
+ // Field 1: fixed int64 value 1000
+ // Field 3: string "field 3"
+ var stream = new MemoryStream();
+ var output = new CodedOutputStream(stream);
+ output.WriteTag(1, WireFormat.WireType.LengthDelimited);
+ output.WriteString("field 1");
+
+ // The outer group...
+ output.WriteTag(2, WireFormat.WireType.StartGroup);
+ output.WriteTag(1, WireFormat.WireType.Fixed32);
+ output.WriteFixed32(100);
+ output.WriteTag(2, WireFormat.WireType.LengthDelimited);
+ output.WriteString("ignore me");
+ // The nested group...
+ output.WriteTag(3, WireFormat.WireType.StartGroup);
+ output.WriteTag(1, WireFormat.WireType.Fixed64);
+ output.WriteFixed64(1000);
+ // Note: Not sure the field number is relevant for end group...
+ output.WriteTag(3, WireFormat.WireType.EndGroup);
+
+ // End the outer group
+ output.WriteTag(2, WireFormat.WireType.EndGroup);
+
+ output.WriteTag(3, WireFormat.WireType.LengthDelimited);
+ output.WriteString("field 3");
+ output.Flush();
+ stream.Position = 0;
+
+ // Now act like a generated client
+ var input = new CodedInputStream(stream);
+ Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited), input.ReadTag());
+ Assert.AreEqual("field 1", input.ReadString());
+ Assert.AreEqual(WireFormat.MakeTag(2, WireFormat.WireType.StartGroup), input.ReadTag());
+ input.SkipLastField(); // Should consume the whole group, including the nested one.
+ Assert.AreEqual(WireFormat.MakeTag(3, WireFormat.WireType.LengthDelimited), input.ReadTag());
+ Assert.AreEqual("field 3", input.ReadString());
+ }
+
+ [Test]
+ public void EndOfStreamReachedWhileSkippingGroup()
+ {
+ var stream = new MemoryStream();
+ var output = new CodedOutputStream(stream);
+ output.WriteTag(1, WireFormat.WireType.StartGroup);
+ output.WriteTag(2, WireFormat.WireType.StartGroup);
+ output.WriteTag(2, WireFormat.WireType.EndGroup);
+
+ output.Flush();
+ stream.Position = 0;
+
+ // Now act like a generated client
+ var input = new CodedInputStream(stream);
+ input.ReadTag();
+ Assert.Throws<InvalidProtocolBufferException>(() => input.SkipLastField());
+ }
+
+ [Test]
+ public void RecursionLimitAppliedWhileSkippingGroup()
+ {
+ var stream = new MemoryStream();
+ var output = new CodedOutputStream(stream);
+ for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)
+ {
+ output.WriteTag(1, WireFormat.WireType.StartGroup);
+ }
+ for (int i = 0; i < CodedInputStream.DefaultRecursionLimit + 1; i++)
+ {
+ output.WriteTag(1, WireFormat.WireType.EndGroup);
+ }
+ output.Flush();
+ stream.Position = 0;
+
+ // Now act like a generated client
+ var input = new CodedInputStream(stream);
+ Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag());
+ Assert.Throws<InvalidProtocolBufferException>(() => input.SkipLastField());
+ }
}
} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
index 6fdd1066..575d4586 100644
--- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs
@@ -629,5 +629,27 @@ namespace Google.Protobuf
var data = new byte[] { 130, 3, 1 };
Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));
}
+
+ /// <summary>
+ /// Demonstrates current behaviour with an extraneous end group tag - see issue 688
+ /// for details; we may want to change this.
+ /// </summary>
+ [Test]
+ public void ExtraEndGroupSkipped()
+ {
+ var message = SampleMessages.CreateFullTestAllTypes();
+ var stream = new MemoryStream();
+ var output = new CodedOutputStream(stream);
+
+ output.WriteTag(100, WireFormat.WireType.EndGroup);
+ output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32);
+ output.WriteFixed32(123);
+
+ output.Flush();
+
+ stream.Position = 0;
+ var parsed = TestAllTypes.Parser.ParseFrom(stream);
+ Assert.AreEqual(new TestAllTypes { SingleFixed32 = 123 }, parsed);
+ }
}
}
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
index f6835c4b..e9e18193 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs
@@ -476,10 +476,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
mapInt32Int32_.AddEntriesFrom(input, _map_mapInt32Int32_codec);
@@ -648,10 +645,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (testMap_ == null) {
@@ -748,10 +742,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
mapInt32Message_.AddEntriesFrom(input, _map_mapInt32Message_codec);
@@ -859,10 +850,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
map1_.AddEntriesFrom(input, _map_map1_codec);
@@ -1156,10 +1144,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
mapInt32Int32_.AddEntriesFrom(input, _map_mapInt32Int32_codec);
@@ -1309,10 +1294,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
type_.AddEntriesFrom(input, _map_type_codec);
@@ -1416,10 +1398,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
entry_.AddEntriesFrom(input, _map_entry_codec);
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
index 646a01a2..bf527ac5 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs
@@ -139,10 +139,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
D = input.ReadInt32();
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
index 225775a3..ec460906 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs
@@ -125,10 +125,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
E = input.ReadInt32();
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
index 1bf40ead..63119a34 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs
@@ -142,10 +142,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -222,10 +219,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -302,10 +296,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -441,10 +432,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
value_ = (global::UnitTest.Issues.TestProtos.NegativeEnum) input.ReadEnum();
@@ -534,10 +522,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -730,10 +715,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
PrimitiveValue = input.ReadInt32();
@@ -860,10 +842,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Item = input.ReadInt32();
@@ -987,10 +966,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Types_ = input.ReadInt32();
@@ -1075,10 +1051,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -1343,10 +1316,7 @@ namespace UnitTest.Issues.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
PlainString = input.ReadString();
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
index 58e5be65..bf4590ad 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs
@@ -1211,10 +1211,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
SingleInt32 = input.ReadInt32();
@@ -1546,10 +1543,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Bb = input.ReadInt32();
@@ -1698,10 +1692,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (child_ == null) {
@@ -1818,10 +1809,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
DeprecatedInt32 = input.ReadInt32();
@@ -1923,10 +1911,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
C = input.ReadInt32();
@@ -2006,10 +1991,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -2110,10 +2092,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (foreignNested_ == null) {
@@ -2240,10 +2219,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
A = input.ReadInt32();
@@ -2374,10 +2350,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (a_ == null) {
@@ -2489,10 +2462,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (bb_ == null) {
@@ -2622,10 +2592,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (a_ == null) {
@@ -2859,10 +2826,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
PrimitiveField = input.ReadInt32();
@@ -3066,10 +3030,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
MyInt = input.ReadInt64();
@@ -3209,10 +3170,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Bb = input.ReadInt32();
@@ -3323,10 +3281,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
sparseEnum_ = (global::Google.Protobuf.TestProtos.TestSparseEnum) input.ReadEnum();
@@ -3428,10 +3383,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Data = input.ReadString();
@@ -3525,10 +3477,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
data_.AddEntriesFrom(input, _repeated_data_codec);
@@ -3630,10 +3579,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Data = input.ReadBytes();
@@ -3735,10 +3681,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Data = input.ReadBytes();
@@ -3840,10 +3783,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Data = input.ReadInt32();
@@ -3945,10 +3885,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Data = input.ReadUInt32();
@@ -4050,10 +3987,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Data = input.ReadInt64();
@@ -4155,10 +4089,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Data = input.ReadUInt64();
@@ -4260,10 +4191,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Data = input.ReadBool();
@@ -4438,10 +4366,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
FooInt = input.ReadInt32();
@@ -4730,10 +4655,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 722:
case 720: {
@@ -5075,10 +4997,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 722:
case 720: {
@@ -5308,10 +5227,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 98:
case 101: {
@@ -5439,10 +5355,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
A = input.ReadString();
@@ -5522,10 +5435,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -5601,10 +5511,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -5680,10 +5587,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -5759,10 +5663,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -5838,10 +5739,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
@@ -5917,10 +5815,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
index 0840fa27..16634e03 100644
--- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
+++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs
@@ -679,10 +679,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
if (anyField_ == null) {
@@ -1136,10 +1133,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
anyField_.AddEntriesFrom(input, _repeated_anyField_codec);
@@ -1757,10 +1751,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
global::Google.Protobuf.WellKnownTypes.Any subBuilder = new global::Google.Protobuf.WellKnownTypes.Any();
@@ -2205,10 +2196,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
anyField_.AddEntriesFrom(input, _map_anyField_codec);
diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
index d2a07057..fbc0ff07 100644
--- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
+++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
@@ -322,5 +322,28 @@ namespace Google.Protobuf.WellKnownTypes
// A normal implementation would have 0 now, as the explicit default would have been overwritten the 5.
Assert.AreEqual(5, message.Int32Field);
}
+
+ [Test]
+ public void UnknownFieldInWrapper()
+ {
+ var stream = new MemoryStream();
+ var output = new CodedOutputStream(stream);
+ var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
+ var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint);
+ var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
+
+ output.WriteTag(wrapperTag);
+ output.WriteLength(4); // unknownTag + value 5 + valueType + value 6, each 1 byte
+ output.WriteTag(unknownTag);
+ output.WriteInt32((int) valueTag); // Sneakily "pretend" it's a tag when it's really a value
+ output.WriteTag(valueTag);
+ output.WriteInt32(6);
+
+ output.Flush();
+ stream.Position = 0;
+
+ var message = TestWellKnownTypes.Parser.ParseFrom(stream);
+ Assert.AreEqual(6, message.Int32Field);
+ }
}
}
diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs
index 2aa62483..3d55f02d 100644
--- a/csharp/src/Google.Protobuf/ByteString.cs
+++ b/csharp/src/Google.Protobuf/ByteString.cs
@@ -40,7 +40,6 @@ namespace Google.Protobuf
{
/// <summary>
/// Immutable array of bytes.
- /// TODO(jonskeet): Implement the common collection interfaces?
/// </summary>
public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
{
@@ -284,8 +283,6 @@ namespace Google.Protobuf
return !(lhs == rhs);
}
- // TODO(jonskeet): CopyTo if it turns out to be required
-
/// <summary>
/// Compares this byte string with another object.
/// </summary>
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index 0e2495f1..c8b33b33 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -30,6 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
+using Google.Protobuf.Collections;
using System;
using System.Collections.Generic;
using System.IO;
@@ -40,20 +41,21 @@ namespace Google.Protobuf
/// Readings and decodes protocol message fields.
/// </summary>
/// <remarks>
- /// This class contains two kinds of methods: methods that read specific
- /// protocol message constructs and field types (e.g. ReadTag and
- /// ReadInt32) and methods that read low-level values (e.g.
- /// ReadRawVarint32 and ReadRawBytes). If you are reading encoded protocol
- /// messages, you should use the former methods, but if you are reading some
- /// other format of your own design, use the latter. The names of the former
- /// methods are taken from the protocol buffer type names, not .NET types.
- /// (Hence ReadFloat instead of ReadSingle, and ReadBool instead of ReadBoolean.)
- ///
- /// TODO(jonskeet): Consider whether recursion and size limits shouldn't be readonly,
- /// set at construction time.
+ /// <para>
+ /// This class is generally used by generated code to read appropriate
+ /// primitives from the stream. It effectively encapsulates the lowest
+ /// levels of protocol buffer format.
+ /// </para>
+ /// <para>
+ /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
+ /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
+ /// </para>
/// </remarks>
public sealed class CodedInputStream
{
+ // TODO(jonskeet): Consider whether recursion and size limits shouldn't be readonly,
+ // set at construction time.
+
/// <summary>
/// Buffer of data read from the stream or provided at construction time.
/// </summary>
@@ -236,17 +238,16 @@ namespace Google.Protobuf
#region Validation
/// <summary>
- /// Verifies that the last call to ReadTag() returned the given tag value.
- /// This is used to verify that a nested group ended with the correct
- /// end tag.
+ /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
+ /// we've reached the end of the stream when we expected to.
/// </summary>
- /// <exception cref="InvalidProtocolBufferException">The last
+ /// <exception cref="InvalidProtocolBufferException">The
/// tag read was not the one specified</exception>
- internal void CheckLastTagWas(uint value)
+ internal void CheckReadEndOfStreamTag()
{
- if (lastTag != value)
+ if (lastTag != 0)
{
- throw InvalidProtocolBufferException.InvalidEndTag();
+ throw InvalidProtocolBufferException.MoreDataAvailable();
}
}
#endregion
@@ -275,6 +276,11 @@ namespace Google.Protobuf
/// <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()
{
@@ -329,22 +335,24 @@ namespace Google.Protobuf
}
/// <summary>
- /// Consumes the data for the field with the tag we've just read.
+ /// Skips the data for the field with the tag we've just read.
/// This should be called directly after <see cref="ReadTag"/>, when
/// the caller wishes to skip an unknown field.
/// </summary>
- public void ConsumeLastField()
+ public void SkipLastField()
{
if (lastTag == 0)
{
- throw new InvalidOperationException("ConsumeLastField cannot be called at the end of a stream");
+ throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
}
switch (WireFormat.GetTagWireType(lastTag))
{
case WireFormat.WireType.StartGroup:
+ SkipGroup();
+ break;
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");
+ // Just ignore; there's no data following the tag.
+ break;
case WireFormat.WireType.Fixed32:
ReadFixed32();
break;
@@ -361,6 +369,29 @@ namespace Google.Protobuf
}
}
+ private void SkipGroup()
+ {
+ // 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...
+ recursionDepth++;
+ if (recursionDepth >= recursionLimit)
+ {
+ throw InvalidProtocolBufferException.RecursionLimitExceeded();
+ }
+ uint tag;
+ do
+ {
+ tag = ReadTag();
+ if (tag == 0)
+ {
+ throw InvalidProtocolBufferException.TruncatedMessage();
+ }
+ // This recursion will allow us to handle nested groups.
+ SkipLastField();
+ } while (WireFormat.GetTagWireType(tag) != WireFormat.WireType.EndGroup);
+ recursionDepth--;
+ }
+
/// <summary>
/// Reads a double field from the stream.
/// </summary>
@@ -475,7 +506,7 @@ namespace Google.Protobuf
int oldLimit = PushLimit(length);
++recursionDepth;
builder.MergeFrom(this);
- CheckLastTagWas(0);
+ CheckReadEndOfStreamTag();
// Check that we've read exactly as much data as expected.
if (!ReachedLimit)
{
@@ -993,7 +1024,6 @@ namespace Google.Protobuf
if (totalBytesRetired + bufferPos + size > currentLimit)
{
// Read to the end of the stream (up to the current limit) anyway.
- // TODO(jonskeet): This is the only usage of SkipRawBytes. Do we really need to do it?
SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.TruncatedMessage();
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs
index 08ea7005..d6355f03 100644
--- a/csharp/src/Google.Protobuf/CodedOutputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs
@@ -30,6 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
+using Google.Protobuf.Collections;
using System;
using System.IO;
using System.Text;
@@ -40,14 +41,19 @@ namespace Google.Protobuf
/// Encodes and writes protocol message fields.
/// </summary>
/// <remarks>
- /// This class contains two kinds of methods: methods that write specific
- /// protocol message constructs and field types (e.g. WriteTag and
- /// WriteInt32) and methods that write low-level values (e.g.
- /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
- /// messages, you should use the former methods, but if you are writing some
- /// other format of your own design, use the latter. The names of the former
- /// methods are taken from the protocol buffer type names, not .NET types.
- /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
+ /// <para>
+ /// This class is generally used by generated code to write appropriate
+ /// primitives to the stream. It effectively encapsulates the lowest
+ /// levels of protocol buffer format. Unlike some other implementations,
+ /// this does not include combined "write tag and value" methods. Generated
+ /// code knows the exact byte representations of the tags they're going to write,
+ /// so there's no need to re-encode them each time. Manually-written code calling
+ /// this class should just call one of the <c>WriteTag</c> overloads before each value.
+ /// </para>
+ /// <para>
+ /// Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>
+ /// and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
+ /// </para>
/// </remarks>
public sealed partial class CodedOutputStream
{
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index 5eb2c2fc..dc4b04cb 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -637,10 +637,9 @@ namespace Google.Protobuf.Collections
{
Value = codec.valueCodec.Read(input);
}
- else if (WireFormat.IsEndGroupTag(tag))
+ else
{
- // TODO(jonskeet): Do we need this? (Given that we don't support groups...)
- return;
+ input.SkipLastField();
}
}
}
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index c901864a..d9ced6ec 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -88,7 +88,7 @@ namespace Google.Protobuf.Collections
public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
{
// TODO: Inline some of the Add code, so we can avoid checking the size on every
- // iteration and the mutability.
+ // iteration.
uint tag = input.LastTag;
var reader = codec.ValueReader;
// Value types can be packed or not.
@@ -315,7 +315,7 @@ namespace Google.Protobuf.Collections
{
throw new ArgumentNullException("values");
}
- // TODO: Check for ICollection and get the Count?
+ // TODO: Check for ICollection and get the Count, to optimize?
foreach (T item in values)
{
Add(item);
@@ -394,7 +394,6 @@ namespace Google.Protobuf.Collections
{
return false;
}
- // TODO(jonskeet): Does this box for enums?
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < count; i++)
{
@@ -418,7 +417,6 @@ namespace Google.Protobuf.Collections
{
throw new ArgumentNullException("item");
}
- // TODO(jonskeet): Does this box for enums?
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < count; i++)
{
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
index 15d52c7d..20a1f438 100644
--- a/csharp/src/Google.Protobuf/FieldCodec.cs
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -304,12 +304,13 @@ namespace Google.Protobuf
{
value = codec.Read(input);
}
- if (WireFormat.IsEndGroupTag(tag))
+ else
{
- break;
+ input.SkipLastField();
}
+
}
- input.CheckLastTagWas(0);
+ input.CheckReadEndOfStreamTag();
input.PopLimit(oldLimit);
return value;
diff --git a/csharp/src/Google.Protobuf/FrameworkPortability.cs b/csharp/src/Google.Protobuf/FrameworkPortability.cs
index 082eb2e1..9498dbe4 100644
--- a/csharp/src/Google.Protobuf/FrameworkPortability.cs
+++ b/csharp/src/Google.Protobuf/FrameworkPortability.cs
@@ -40,10 +40,9 @@ namespace Google.Protobuf
/// </summary>
internal static class FrameworkPortability
{
- // TODO(jtattermusch): is this still a thing?
// The value of RegexOptions.Compiled is 8. We can test for the presence at
// execution time using Enum.IsDefined, so a single build will do the right thing
- // on each platform.
+ // on each platform. (RegexOptions.Compiled isn't supported by PCLs.)
internal static readonly RegexOptions CompiledRegexWhereAvailable =
Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None;
}
diff --git a/csharp/src/Google.Protobuf/IMessage.cs b/csharp/src/Google.Protobuf/IMessage.cs
index 147c83ca..773845ff 100644
--- a/csharp/src/Google.Protobuf/IMessage.cs
+++ b/csharp/src/Google.Protobuf/IMessage.cs
@@ -35,8 +35,6 @@ using Google.Protobuf.Reflection;
namespace Google.Protobuf
{
-
- // TODO(jonskeet): Do we want a "weak" (non-generic) version of IReflectedMessage?
// TODO(jonskeet): Split these interfaces into separate files when we're happy with them.
/// <summary>
diff --git a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
index 6905a6a3..01d55395 100644
--- a/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
+++ b/csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
@@ -45,6 +45,12 @@ namespace Google.Protobuf
{
}
+ internal static InvalidProtocolBufferException MoreDataAvailable()
+ {
+ return new InvalidProtocolBufferException(
+ "Completed reading a message while more data was available in the stream.");
+ }
+
internal static InvalidProtocolBufferException TruncatedMessage()
{
return new InvalidProtocolBufferException(
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index 7c4894be..12bbdfdd 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -158,7 +158,6 @@ namespace Google.Protobuf
{
var accessor = field.Accessor;
// Oneofs are written later
- // TODO: Change to write out fields in order, interleaving oneofs appropriately (as per binary format)
if (field.ContainingOneof != null && field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) != field)
{
continue;
@@ -425,7 +424,7 @@ namespace Google.Protobuf
if (descriptor.FullName == ListValue.Descriptor.FullName)
{
var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
- WriteList(builder, fieldAccessor, (IList) fieldAccessor.GetValue(value));
+ WriteList(builder, fieldAccessor, (IList) fieldAccessor.GetValue((IMessage) value));
return;
}
if (descriptor.FullName == Value.Descriptor.FullName)
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
index ee78dc8d..d2d057c0 100644
--- a/csharp/src/Google.Protobuf/MessageExtensions.cs
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -50,7 +50,7 @@ namespace Google.Protobuf
Preconditions.CheckNotNull(data, "data");
CodedInputStream input = new CodedInputStream(data);
message.MergeFrom(input);
- input.CheckLastTagWas(0);
+ input.CheckReadEndOfStreamTag();
}
/// <summary>
@@ -64,7 +64,7 @@ namespace Google.Protobuf
Preconditions.CheckNotNull(data, "data");
CodedInputStream input = data.CreateCodedInput();
message.MergeFrom(input);
- input.CheckLastTagWas(0);
+ input.CheckReadEndOfStreamTag();
}
/// <summary>
@@ -78,7 +78,7 @@ namespace Google.Protobuf
Preconditions.CheckNotNull(input, "input");
CodedInputStream codedInput = new CodedInputStream(input);
message.MergeFrom(codedInput);
- codedInput.CheckLastTagWas(0);
+ codedInput.CheckReadEndOfStreamTag();
}
/// <summary>
diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
index d66bdb80..59c5e69b 100644
--- a/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
@@ -242,10 +242,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
file_.AddEntriesFrom(input, _repeated_file_codec);
@@ -539,10 +536,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -833,10 +827,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -1000,10 +991,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Start = input.ReadInt32();
@@ -1131,10 +1119,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Start = input.ReadInt32();
@@ -1424,10 +1409,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -1597,10 +1579,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -1741,10 +1720,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -1904,10 +1880,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -2059,10 +2032,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -2288,10 +2258,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -2716,10 +2683,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
JavaPackage = input.ReadString();
@@ -2969,10 +2933,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
MessageSetWireFormat = input.ReadBool();
@@ -3214,10 +3175,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
ctype_ = (global::Google.Protobuf.Reflection.FieldOptions.Types.CType) input.ReadEnum();
@@ -3397,10 +3355,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 16: {
AllowAlias = input.ReadBool();
@@ -3524,10 +3479,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Deprecated = input.ReadBool();
@@ -3647,10 +3599,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 264: {
Deprecated = input.ReadBool();
@@ -3770,10 +3719,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 264: {
Deprecated = input.ReadBool();
@@ -4003,10 +3949,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 18: {
name_.AddEntriesFrom(input, _repeated_name_codec);
@@ -4155,10 +4098,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
NamePart_ = input.ReadString();
@@ -4261,10 +4201,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
location_.AddEntriesFrom(input, _repeated_location_codec);
@@ -4431,10 +4368,7 @@ namespace Google.Protobuf.Reflection {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10:
case 8: {
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
index 3fccf884..82ce5051 100644
--- a/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FieldAccessorBase.cs
@@ -41,23 +41,23 @@ namespace Google.Protobuf.Reflection
/// </summary>
internal abstract class FieldAccessorBase : IFieldAccessor
{
- private readonly Func<object, object> getValueDelegate;
+ private readonly Func<IMessage, object> getValueDelegate;
private readonly FieldDescriptor descriptor;
internal FieldAccessorBase(PropertyInfo property, FieldDescriptor descriptor)
{
this.descriptor = descriptor;
- getValueDelegate = ReflectionUtil.CreateFuncObjectObject(property.GetGetMethod());
+ getValueDelegate = ReflectionUtil.CreateFuncIMessageObject(property.GetGetMethod());
}
public FieldDescriptor Descriptor { get { return descriptor; } }
- public object GetValue(object message)
+ public object GetValue(IMessage message)
{
return getValueDelegate(message);
}
- public abstract void Clear(object message);
- public abstract void SetValue(object message, object value);
+ public abstract void Clear(IMessage message);
+ public abstract void SetValue(IMessage message, object value);
}
}
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index 72927702..500e467c 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -287,23 +287,23 @@ namespace Google.Protobuf.Reflection
DescriptorPool pool = new DescriptorPool(dependencies);
FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo);
- // TODO(jonskeet): Reinstate these checks, or get rid of them entirely. They aren't in the Java code,
- // and fail for the CustomOptions test right now. (We get "descriptor.proto" vs "google/protobuf/descriptor.proto".)
- //if (dependencies.Length != proto.DependencyCount)
- //{
- // throw new DescriptorValidationException(result,
- // "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
- // "those listed in the FileDescriptorProto.");
- //}
- //for (int i = 0; i < proto.DependencyCount; i++)
- //{
- // if (dependencies[i].Name != proto.DependencyList[i])
- // {
- // throw new DescriptorValidationException(result,
- // "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
- // "those listed in the FileDescriptorProto.");
- // }
- //}
+ // Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we
+ // need.
+ if (dependencies.Length != proto.Dependency.Count)
+ {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ for (int i = 0; i < proto.Dependency.Count; i++)
+ {
+ if (dependencies[i].Name != proto.Dependency[i])
+ {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ }
result.CrossLink();
return result;
diff --git a/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
index f97d73ee..cfe56fde 100644
--- a/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/IFieldAccessor.cs
@@ -45,20 +45,18 @@ namespace Google.Protobuf.Reflection
/// </summary>
FieldDescriptor Descriptor { get; }
- // TODO: Should the argument type for these messages be IReflectedMessage?
-
/// <summary>
/// Clears the field in the specified message. (For repeated fields,
/// this clears the list.)
/// </summary>
- void Clear(object message);
+ void Clear(IMessage message);
/// <summary>
/// Fetches the field value. For repeated values, this will be an
/// <see cref="IList"/> implementation. For map values, this will be an
/// <see cref="IDictionary"/> implementation.
/// </summary>
- object GetValue(object message);
+ object GetValue(IMessage message);
/// <summary>
/// Mutator for single "simple" fields only.
@@ -68,6 +66,6 @@ namespace Google.Protobuf.Reflection
/// Map fields are mutated by fetching the value and manipulating it as a dictionary.
/// </remarks>
/// <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
- void SetValue(object message, object value);
+ void SetValue(IMessage message, object value);
}
} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
index 6df4c5f0..9ed7f8c4 100644
--- a/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MapFieldAccessor.cs
@@ -45,13 +45,13 @@ namespace Google.Protobuf.Reflection
{
}
- public override void Clear(object message)
+ public override void Clear(IMessage message)
{
IDictionary list = (IDictionary) GetValue(message);
list.Clear();
}
- public override void SetValue(object message, object value)
+ public override void SetValue(IMessage message, object value)
{
throw new InvalidOperationException("SetValue is not implemented for map fields");
}
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
index ff51291b..8714ab18 100644
--- a/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs
@@ -41,8 +41,8 @@ namespace Google.Protobuf.Reflection
/// </summary>
public sealed class OneofAccessor
{
- private readonly Func<object, int> caseDelegate;
- private readonly Action<object> clearDelegate;
+ private readonly Func<IMessage, int> caseDelegate;
+ private readonly Action<IMessage> clearDelegate;
private OneofDescriptor descriptor;
internal OneofAccessor(PropertyInfo caseProperty, MethodInfo clearMethod, OneofDescriptor descriptor)
@@ -52,10 +52,10 @@ namespace Google.Protobuf.Reflection
throw new ArgumentException("Cannot read from property");
}
this.descriptor = descriptor;
- caseDelegate = ReflectionUtil.CreateFuncObjectT<int>(caseProperty.GetGetMethod());
+ caseDelegate = ReflectionUtil.CreateFuncIMessageT<int>(caseProperty.GetGetMethod());
this.descriptor = descriptor;
- clearDelegate = ReflectionUtil.CreateActionObject(clearMethod);
+ clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
}
/// <summary>
@@ -69,7 +69,7 @@ namespace Google.Protobuf.Reflection
/// <summary>
/// Clears the oneof in the specified message.
/// </summary>
- public void Clear(object message)
+ public void Clear(IMessage message)
{
clearDelegate(message);
}
@@ -77,7 +77,7 @@ namespace Google.Protobuf.Reflection
/// <summary>
/// Indicates which field in the oneof is set for specified message
/// </summary>
- public FieldDescriptor GetCaseFieldDescriptor(object message)
+ public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
{
int fieldNumber = caseDelegate(message);
if (fieldNumber > 0)
diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
index 5b3cbb36..df820ca3 100644
--- a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
+++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
@@ -56,52 +56,52 @@ namespace Google.Protobuf.Reflection
/// Creates a delegate which will cast the argument to the appropriate method target type,
/// call the method on it, then convert the result to object.
/// </summary>
- internal static Func<object, object> CreateFuncObjectObject(MethodInfo method)
+ internal static Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method)
{
- ParameterExpression parameter = Expression.Parameter(typeof(object), "p");
+ ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
Expression downcast = Expression.Convert(parameter, method.DeclaringType);
Expression call = Expression.Call(downcast, method);
Expression upcast = Expression.Convert(call, typeof(object));
- return Expression.Lambda<Func<object, object>>(upcast, parameter).Compile();
+ return Expression.Lambda<Func<IMessage, object>>(upcast, parameter).Compile();
}
/// <summary>
/// Creates a delegate which will cast the argument to the appropriate method target type,
/// call the method on it, then convert the result to the specified type.
/// </summary>
- internal static Func<object, T> CreateFuncObjectT<T>(MethodInfo method)
+ internal static Func<IMessage, T> CreateFuncIMessageT<T>(MethodInfo method)
{
- ParameterExpression parameter = Expression.Parameter(typeof(object), "p");
+ ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
Expression downcast = Expression.Convert(parameter, method.DeclaringType);
Expression call = Expression.Call(downcast, method);
Expression upcast = Expression.Convert(call, typeof(T));
- return Expression.Lambda<Func<object, T>>(upcast, parameter).Compile();
+ return Expression.Lambda<Func<IMessage, T>>(upcast, parameter).Compile();
}
/// <summary>
/// Creates a delegate which will execute the given method after casting the first argument to
/// the target type of the method, and the second argument to the first parameter type of the method.
/// </summary>
- internal static Action<object, object> CreateActionObjectObject(MethodInfo method)
+ internal static Action<IMessage, object> CreateActionIMessageObject(MethodInfo method)
{
- ParameterExpression targetParameter = Expression.Parameter(typeof(object), "target");
+ ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
Expression call = Expression.Call(castTarget, method, castArgument);
- return Expression.Lambda<Action<object, object>>(call, targetParameter, argParameter).Compile();
+ return Expression.Lambda<Action<IMessage, object>>(call, targetParameter, argParameter).Compile();
}
/// <summary>
/// Creates a delegate which will execute the given method after casting the first argument to
/// the target type of the method.
/// </summary>
- internal static Action<object> CreateActionObject(MethodInfo method)
+ internal static Action<IMessage> CreateActionIMessage(MethodInfo method)
{
- ParameterExpression targetParameter = Expression.Parameter(typeof(object), "target");
+ ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
Expression call = Expression.Call(castTarget, method);
- return Expression.Lambda<Action<object>>(call, targetParameter).Compile();
+ return Expression.Lambda<Action<IMessage>>(call, targetParameter).Compile();
}
}
} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
index acb3c8d5..bd408470 100644
--- a/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/RepeatedFieldAccessor.cs
@@ -45,13 +45,13 @@ namespace Google.Protobuf.Reflection
{
}
- public override void Clear(object message)
+ public override void Clear(IMessage message)
{
IList list = (IList) GetValue(message);
list.Clear();
}
- public override void SetValue(object message, object value)
+ public override void SetValue(IMessage message, object value)
{
throw new InvalidOperationException("SetValue is not implemented for repeated fields");
}
diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
index 851efc26..de92fbc1 100644
--- a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
@@ -46,8 +46,8 @@ namespace Google.Protobuf.Reflection
// and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
// values.
- private readonly Action<object, object> setValueDelegate;
- private readonly Action<object> clearDelegate;
+ private readonly Action<IMessage, object> setValueDelegate;
+ private readonly Action<IMessage> clearDelegate;
internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
{
@@ -55,12 +55,10 @@ namespace Google.Protobuf.Reflection
{
throw new ArgumentException("Not all required properties/methods available");
}
- setValueDelegate = ReflectionUtil.CreateActionObjectObject(property.GetSetMethod());
+ setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
var clrType = property.PropertyType;
- // TODO: What should clear on a oneof member do? Clear the oneof?
-
// TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
object defaultValue =
typeof(IMessage).IsAssignableFrom(clrType) ? null
@@ -70,12 +68,12 @@ namespace Google.Protobuf.Reflection
clearDelegate = message => SetValue(message, defaultValue);
}
- public override void Clear(object message)
+ public override void Clear(IMessage message)
{
clearDelegate(message);
}
- public override void SetValue(object message, object value)
+ public override void SetValue(IMessage message, object value)
{
setValueDelegate(message, value);
}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
index 9fc653b0..204b37cf 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
@@ -150,10 +150,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
TypeUrl = input.ReadString();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
index 8a94e7b0..a5f95093 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs
@@ -213,10 +213,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -439,10 +436,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
index d74636d4..aa34f2d8 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs
@@ -151,10 +151,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Seconds = input.ReadInt64();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
index 0f1d7f50..7d699c1d 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs
@@ -106,10 +106,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
}
}
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
index 9bd47a96..0dac4403 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs
@@ -120,10 +120,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
paths_.AddEntriesFrom(input, _repeated_paths_codec);
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
index ae79884f..8347999d 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs
@@ -129,10 +129,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
FileName = input.ReadString();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
index ea8b1055..1e8a8236 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs
@@ -139,10 +139,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
fields_.AddEntriesFrom(input, _map_fields_codec);
@@ -392,10 +389,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
kind_ = input.ReadEnum();
@@ -520,10 +514,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
values_.AddEntriesFrom(input, _repeated_values_codec);
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
index 89355bdc..d7c0954f 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -151,10 +151,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Seconds = input.ReadInt64();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
index 36116a65..ff2ecc57 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs
@@ -226,10 +226,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -496,10 +493,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
kind_ = (global::Google.Protobuf.WellKnownTypes.Field.Types.Kind) input.ReadEnum();
@@ -716,10 +710,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -872,10 +863,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
@@ -1010,10 +998,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Name = input.ReadString();
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
index 19ed599d..9ecaf47c 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs
@@ -138,10 +138,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 9: {
Value = input.ReadDouble();
@@ -243,10 +240,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 13: {
Value = input.ReadFloat();
@@ -348,10 +342,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Value = input.ReadInt64();
@@ -453,10 +444,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Value = input.ReadUInt64();
@@ -558,10 +546,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Value = input.ReadInt32();
@@ -663,10 +648,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Value = input.ReadUInt32();
@@ -768,10 +750,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 8: {
Value = input.ReadBool();
@@ -873,10 +852,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Value = input.ReadString();
@@ -978,10 +954,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- return;
- }
- input.ConsumeLastField();
+ input.SkipLastField();
break;
case 10: {
Value = input.ReadBytes();
diff --git a/csharp/src/Google.Protobuf/WireFormat.cs b/csharp/src/Google.Protobuf/WireFormat.cs
index bbd7e4f9..faf1e715 100644
--- a/csharp/src/Google.Protobuf/WireFormat.cs
+++ b/csharp/src/Google.Protobuf/WireFormat.cs
@@ -43,19 +43,6 @@ namespace Google.Protobuf
/// </summary>
public static class WireFormat
{
- #region Fixed sizes.
-
- // TODO(jonskeet): Move these somewhere else. They're messy. Consider making FieldType a smarter kind of enum
- internal const int Fixed32Size = 4;
- internal const int Fixed64Size = 8;
- internal const int SFixed32Size = 4;
- internal const int SFixed64Size = 8;
- internal const int FloatSize = 4;
- internal const int DoubleSize = 8;
- internal const int BoolSize = 1;
-
- #endregion
-
/// <summary>
/// Wire types within protobuf encoding.
/// </summary>
@@ -99,16 +86,6 @@ namespace Google.Protobuf
}
/// <summary>
- /// Determines whether the given tag is an end group tag.
- /// </summary>
- /// <param name="tag">The tag to check.</param>
- /// <returns><c>true</c> if the given tag is an end group tag; <c>false</c> otherwise.</returns>
- public static bool IsEndGroupTag(uint tag)
- {
- return (WireType) (tag & TagTypeMask) == WireType.EndGroup;
- }
-
- /// <summary>
/// Given a tag value, determines the field number (the upper 29 bits).
/// </summary>
public static int GetTagFieldNumber(uint tag)
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
index 40c13de5..a71a7909 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -423,10 +423,7 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
printer->Indent();
printer->Print(
"default:\n"
- " if (pb::WireFormat.IsEndGroupTag(tag)) {\n"
- " return;\n"
- " }\n"
- " input.ConsumeLastField();\n" // We're not storing the data, but we still need to consume it.
+ " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it.
" break;\n");
for (int i = 0; i < fields_by_number().size(); i++) {
const FieldDescriptor* field = fields_by_number()[i];