diff --git a/csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs b/csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs
index 8332140e5d..c2b2a83219 100644
--- a/csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs
+++ b/csharp/ProtocolBuffers.Test/CodedInputStreamTest.cs
@@ -118,7 +118,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using ReadRawLittleEndian32() and checks
/// that the result matches the given value.
///
- private static void AssertReadLittleEndian32(byte[] data, int value) {
+ private static void AssertReadLittleEndian32(byte[] data, uint value) {
CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian32());
@@ -134,7 +134,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using ReadRawLittleEndian64() and checks
/// that the result matches the given value.
///
- private static void AssertReadLittleEndian64(byte[] data, long value) {
+ private static void AssertReadLittleEndian64(byte[] data, ulong value) {
CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian64());
@@ -149,12 +149,12 @@ namespace Google.ProtocolBuffers {
[Test]
public void ReadLittleEndian() {
AssertReadLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
- AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), unchecked((int)0x9abcdef0));
+ AssertReadLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
AssertReadLittleEndian64(Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
AssertReadLittleEndian64(
- Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), unchecked((long)0x9abcdef012345678L));
+ Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678UL);
}
[Test]
diff --git a/csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs b/csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs
index 0e97f2fd9f..f2f00dfeb9 100644
--- a/csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs
+++ b/csharp/ProtocolBuffers.Test/CodedOutputStreamTest.cs
@@ -106,7 +106,7 @@ namespace Google.ProtocolBuffers {
AssertWriteVarint(
Bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
- (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ (0x43UL << 28) | (0x49L << 35) | (0x24UL << 42) | (0x49UL << 49));
// 11964378330978735131
AssertWriteVarint(
Bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
@@ -120,7 +120,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using WriteRawLittleEndian32() and checks
/// that the result matches the given value.
///
- private static void AssertWriteLittleEndian32(byte[] data, int value) {
+ private static void AssertWriteLittleEndian32(byte[] data, uint value) {
MemoryStream rawOutput = new MemoryStream();
CodedOutputStream output = CodedOutputStream.CreateInstance(rawOutput);
output.WriteRawLittleEndian32(value);
@@ -141,7 +141,7 @@ namespace Google.ProtocolBuffers {
/// Parses the given bytes using WriteRawLittleEndian64() and checks
/// that the result matches the given value.
///
- private static void AssertWriteLittleEndian64(byte[] data, long value) {
+ private static void AssertWriteLittleEndian64(byte[] data, ulong value) {
MemoryStream rawOutput = new MemoryStream();
CodedOutputStream output = CodedOutputStream.CreateInstance(rawOutput);
output.WriteRawLittleEndian64(value);
@@ -164,14 +164,14 @@ namespace Google.ProtocolBuffers {
[Test]
public void WriteLittleEndian() {
AssertWriteLittleEndian32(Bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
- AssertWriteLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), unchecked((int)0x9abcdef0));
+ AssertWriteLittleEndian32(Bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
AssertWriteLittleEndian64(
Bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
AssertWriteLittleEndian64(
Bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
- unchecked((long)0x9abcdef012345678L));
+ 0x9abcdef012345678UL);
}
/* TODO(jonskeet): Put this back when we've got the rest working!
diff --git a/csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj b/csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
index 89c5507af6..28c86b3ce4 100644
--- a/csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
+++ b/csharp/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
@@ -48,6 +48,7 @@
+
diff --git a/csharp/ProtocolBuffers.Test/WireFormatTest.cs b/csharp/ProtocolBuffers.Test/WireFormatTest.cs
new file mode 100644
index 0000000000..87c9dc6d3e
--- /dev/null
+++ b/csharp/ProtocolBuffers.Test/WireFormatTest.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NUnit.Framework;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers {
+ [TestFixture]
+ public class WireFormatTest {
+
+ [Test]
+ public void FieldTypeToWireTypeMapping() {
+
+ // Just test a few values
+ Assert.AreEqual(WireFormat.WireType.Fixed64, WireFormat.FieldTypeToWireFormatMap[FieldType.SFixed64]);
+ Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.String]);
+ Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.Message]);
+ }
+ }
+}
diff --git a/csharp/ProtocolBuffers/AbstractBuilder.cs b/csharp/ProtocolBuffers/AbstractBuilder.cs
index f8ed554da5..8a8554e443 100644
--- a/csharp/ProtocolBuffers/AbstractBuilder.cs
+++ b/csharp/ProtocolBuffers/AbstractBuilder.cs
@@ -25,7 +25,7 @@ namespace Google.ProtocolBuffers {
protected abstract IMessage BuildPartialImpl();
protected abstract IBuilder CloneImpl();
protected abstract IMessage DefaultInstanceForTypeImpl { get; }
- protected abstract IBuilder NewBuilderForFieldImpl(FieldDescriptor field);
+ protected abstract IBuilder CreateBuilderForFieldImpl(FieldDescriptor field);
protected abstract IBuilder ClearFieldImpl(FieldDescriptor field);
protected abstract IBuilder AddRepeatedFieldImpl(FieldDescriptor field, object value);
#endregion
@@ -47,8 +47,8 @@ namespace Google.ProtocolBuffers {
get { return DefaultInstanceForTypeImpl; }
}
- IBuilder IBuilder.NewBuilderForField(FieldDescriptor field) {
- return NewBuilderForFieldImpl(field);
+ IBuilder IBuilder.CreateBuilderForField(FieldDescriptor field) {
+ return CreateBuilderForFieldImpl(field);
}
IBuilder IBuilder.ClearField(FieldDescriptor field) {
diff --git a/csharp/ProtocolBuffers/Autogenerated.cs b/csharp/ProtocolBuffers/Autogenerated.cs
index 5b999787f4..e4aee669f0 100644
--- a/csharp/ProtocolBuffers/Autogenerated.cs
+++ b/csharp/ProtocolBuffers/Autogenerated.cs
@@ -5,5 +5,11 @@ namespace Google.ProtocolBuffers {
public class MessageOptions {
public bool IsMessageSetWireFormat;
}
+
+ public class EnumValueDescriptorProto {
+ }
+
+ public class FieldDescriptorProto {
+ }
}
}
diff --git a/csharp/ProtocolBuffers/CodedInputStream.cs b/csharp/ProtocolBuffers/CodedInputStream.cs
index d2a3657b42..ff5d6f885f 100644
--- a/csharp/ProtocolBuffers/CodedInputStream.cs
+++ b/csharp/ProtocolBuffers/CodedInputStream.cs
@@ -142,7 +142,7 @@ namespace Google.ProtocolBuffers {
/// Read a double field from the stream.
///
public double ReadDouble() {
- return BitConverter.Int64BitsToDouble(ReadRawLittleEndian64());
+ return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
}
///
@@ -178,14 +178,14 @@ namespace Google.ProtocolBuffers {
///
/// Read a fixed64 field from the stream.
///
- public long ReadFixed64() {
+ public ulong ReadFixed64() {
return ReadRawLittleEndian64();
}
///
/// Read a fixed32 field from the stream.
///
- public int ReadFixed32() {
+ public uint ReadFixed32() {
return ReadRawLittleEndian32();
}
@@ -293,14 +293,14 @@ namespace Google.ProtocolBuffers {
/// Reads an sfixed32 field value from the stream.
///
public int ReadSFixed32() {
- return ReadRawLittleEndian32();
+ return (int) ReadRawLittleEndian32();
}
///
/// Reads an sfixed64 field value from the stream.
///
public long ReadSFixed64() {
- return ReadRawLittleEndian64();
+ return (long) ReadRawLittleEndian64();
}
///
@@ -410,26 +410,26 @@ namespace Google.ProtocolBuffers {
///
/// Read a 32-bit little-endian integer from the stream.
///
- public int ReadRawLittleEndian32() {
- byte b1 = ReadRawByte();
- byte b2 = ReadRawByte();
- byte b3 = ReadRawByte();
- byte b4 = ReadRawByte();
+ public uint ReadRawLittleEndian32() {
+ uint b1 = ReadRawByte();
+ uint b2 = ReadRawByte();
+ uint b3 = ReadRawByte();
+ uint b4 = ReadRawByte();
return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
}
///
/// Read a 64-bit little-endian integer from the stream.
///
- public long ReadRawLittleEndian64() {
- long b1 = ReadRawByte();
- long b2 = ReadRawByte();
- long b3 = ReadRawByte();
- long b4 = ReadRawByte();
- long b5 = ReadRawByte();
- long b6 = ReadRawByte();
- long b7 = ReadRawByte();
- long b8 = ReadRawByte();
+ public ulong ReadRawLittleEndian64() {
+ ulong b1 = ReadRawByte();
+ ulong b2 = ReadRawByte();
+ ulong b3 = ReadRawByte();
+ ulong b4 = ReadRawByte();
+ ulong b5 = ReadRawByte();
+ ulong b6 = ReadRawByte();
+ ulong b7 = ReadRawByte();
+ ulong b8 = ReadRawByte();
return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
| (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
}
@@ -705,6 +705,51 @@ namespace Google.ProtocolBuffers {
}
}
+ ///
+ /// Reads and discards a single field, given its tag value.
+ ///
+ /// false if the tag is an end-group tag, in which case
+ /// nothing is skipped. Otherwise, returns true.
+ public bool SkipField(uint tag) {
+ switch (WireFormat.GetTagWireType(tag)) {
+ case WireFormat.WireType.Varint:
+ ReadInt32();
+ return true;
+ case WireFormat.WireType.Fixed64:
+ ReadRawLittleEndian64();
+ return true;
+ case WireFormat.WireType.LengthDelimited:
+ SkipRawBytes((int) ReadRawVarint32());
+ return true;
+ case WireFormat.WireType.StartGroup:
+ SkipMessage();
+ CheckLastTagWas(
+ WireFormat.MakeTag(WireFormat.GetTagFieldNumber(tag),
+ WireFormat.WireType.EndGroup));
+ return true;
+ case WireFormat.WireType.EndGroup:
+ return false;
+ case WireFormat.WireType.Fixed32:
+ ReadRawLittleEndian32();
+ return true;
+ default:
+ throw InvalidProtocolBufferException.InvalidWireType();
+ }
+ }
+
+ ///
+ /// Reads and discards an entire message. This will read either until EOF
+ /// or until an endgroup tag, whichever comes first.
+ ///
+ public void SkipMessage() {
+ while (true) {
+ uint tag = ReadTag();
+ if (tag == 0 || !SkipField(tag)) {
+ return;
+ }
+ }
+ }
+
///
/// Reads and discards bytes.
///
diff --git a/csharp/ProtocolBuffers/CodedOutputStream.cs b/csharp/ProtocolBuffers/CodedOutputStream.cs
index 5fec52743f..260db868a3 100644
--- a/csharp/ProtocolBuffers/CodedOutputStream.cs
+++ b/csharp/ProtocolBuffers/CodedOutputStream.cs
@@ -99,7 +99,7 @@ namespace Google.ProtocolBuffers {
///
public void WriteDouble(int fieldNumber, double value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
- WriteRawLittleEndian64(BitConverter.DoubleToInt64Bits(value));
+ WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
}
///
@@ -143,7 +143,7 @@ namespace Google.ProtocolBuffers {
///
/// Writes a fixed64 field value, including tag, to the stream.
///
- public void WriteFixed64(int fieldNumber, long value) {
+ public void WriteFixed64(int fieldNumber, ulong value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
WriteRawLittleEndian64(value);
}
@@ -151,7 +151,7 @@ namespace Google.ProtocolBuffers {
///
/// Writes a fixed32 field value, including tag, to the stream.
///
- public void WriteFixed32(int fieldNumber, int value) {
+ public void WriteFixed32(int fieldNumber, uint value) {
WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
WriteRawLittleEndian32(value);
}
@@ -259,8 +259,8 @@ namespace Google.ProtocolBuffers {
case FieldType.Int64: WriteInt64(fieldNumber, (long)value); break;
case FieldType.UInt64: WriteUInt64(fieldNumber, (ulong)value); break;
case FieldType.Int32: WriteInt32(fieldNumber, (int)value); break;
- case FieldType.Fixed64: WriteFixed64(fieldNumber, (long)value); break;
- case FieldType.Fixed32: WriteFixed32(fieldNumber, (int)value); break;
+ case FieldType.Fixed64: WriteFixed64(fieldNumber, (ulong)value); break;
+ case FieldType.Fixed32: WriteFixed32(fieldNumber, (uint)value); break;
case FieldType.Bool: WriteBool(fieldNumber, (bool)value); break;
case FieldType.String: WriteString(fieldNumber, (string)value); break;
case FieldType.Group: WriteGroup(fieldNumber, (IMessage)value); break;
@@ -310,14 +310,14 @@ namespace Google.ProtocolBuffers {
}
}
- public void WriteRawLittleEndian32(int value) {
+ public void WriteRawLittleEndian32(uint value) {
WriteRawByte((byte)value);
WriteRawByte((byte)(value >> 8));
WriteRawByte((byte)(value >> 16));
WriteRawByte((byte)(value >> 24));
}
- public void WriteRawLittleEndian64(long value) {
+ public void WriteRawLittleEndian64(ulong value) {
WriteRawByte((byte)value);
WriteRawByte((byte)(value >> 8));
WriteRawByte((byte)(value >> 16));
diff --git a/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs
index c4f5c7964d..2d27b1f052 100644
--- a/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/EnumDescriptor.cs
@@ -1,5 +1,8 @@
namespace Google.ProtocolBuffers.Descriptors {
public class EnumDescriptor {
+ internal EnumValueDescriptor FindValueByNumber(int rawValue) {
+ throw new System.NotImplementedException();
+ }
}
}
diff --git a/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs
index 48b3fb5c7f..faa83fd430 100644
--- a/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs
@@ -2,6 +2,14 @@
namespace Google.ProtocolBuffers.Descriptors {
public class EnumValueDescriptor {
+
+ internal EnumValueDescriptor(DescriptorProtos.EnumValueDescriptorProto proto,
+ FileDescriptor file,
+ EnumDescriptor parent,
+ int index) {
+ enumDescriptor = parent;
+ }
+
private EnumDescriptor enumDescriptor;
public int Number {
diff --git a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
index 45e7f96450..cd2f19b154 100644
--- a/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/FieldDescriptor.cs
@@ -1,9 +1,19 @@
-
-using System;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Google.ProtocolBuffers.Collections;
namespace Google.ProtocolBuffers.Descriptors {
public class FieldDescriptor {
+ private FieldDescriptor(DescriptorProtos.FieldDescriptorProto proto,
+ FileDescriptor file,
+ MessageDescriptor parent,
+ int index,
+ bool isExtension) {
+ enumType = null;
+ }
+
private EnumDescriptor enumType;
public bool IsRequired {
@@ -47,14 +57,28 @@ namespace Google.ProtocolBuffers.Descriptors {
/// this will always be an empty list. For message fields it will
/// always be null. For singular values, it will depend on the descriptor.
///
- public object DefaultValue
- {
+ public object DefaultValue {
get { throw new NotImplementedException(); }
}
- public string Name
- {
+ public string Name {
get { throw new NotImplementedException(); }
}
+
+ ///
+ /// Immutable mapping from field type to mapped type. Built using the attributes on
+ /// FieldType values.
+ ///
+ public static readonly IDictionary FieldTypeToWireFormatMap = MapFieldTypes();
+
+ private static IDictionary MapFieldTypes() {
+ var map = new Dictionary();
+ foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) {
+ FieldType fieldType = (FieldType)field.GetValue(null);
+ FieldMappingAttribute mapping = (FieldMappingAttribute)field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0];
+ map[fieldType] = mapping.MappedType;
+ }
+ return Dictionaries.AsReadOnly(map);
+ }
}
}
diff --git a/csharp/ProtocolBuffers/Descriptors/FieldMappingAttribute.cs b/csharp/ProtocolBuffers/Descriptors/FieldMappingAttribute.cs
new file mode 100644
index 0000000000..13e8be1ecc
--- /dev/null
+++ b/csharp/ProtocolBuffers/Descriptors/FieldMappingAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Google.ProtocolBuffers.Descriptors {
+
+ ///
+ /// Defined specifically for the enumeration,
+ /// this allows each field type to specify the mapped type and wire type.
+ ///
+ [AttributeUsage(AttributeTargets.Field)]
+ internal class FieldMappingAttribute : Attribute {
+ internal FieldMappingAttribute(MappedType mappedType, WireFormat.WireType wireType) {
+ MappedType = mappedType;
+ WireType = wireType;
+ }
+
+ internal MappedType MappedType { get; private set; }
+ internal WireFormat.WireType WireType { get; private set; }
+ }
+}
diff --git a/csharp/ProtocolBuffers/Descriptors/FieldType.cs b/csharp/ProtocolBuffers/Descriptors/FieldType.cs
index d54ded53cc..30b82d6926 100644
--- a/csharp/ProtocolBuffers/Descriptors/FieldType.cs
+++ b/csharp/ProtocolBuffers/Descriptors/FieldType.cs
@@ -1,23 +1,27 @@
namespace Google.ProtocolBuffers.Descriptors {
+ ///
+ /// Enumeration of all the possible field types. The odd formatting is to make it very clear
+ /// which attribute applies to which value, while maintaining a compact format.
+ ///
public enum FieldType {
- Double,
- Float,
- Int64,
- UInt64,
- Int32,
- Fixed64,
- Fixed32,
- Bool,
- String,
- Group,
- Message,
- Bytes,
- UInt32,
- SFixed32,
- SFixed64,
- SInt32,
- SInt64,
- Enum
+ [FieldMapping(MappedType.Double, WireFormat.WireType.Fixed64)] Double,
+ [FieldMapping(MappedType.Single, WireFormat.WireType.Fixed32)] Float,
+ [FieldMapping(MappedType.Int64, WireFormat.WireType.Varint)] Int64,
+ [FieldMapping(MappedType.UInt64, WireFormat.WireType.Varint)] UInt64,
+ [FieldMapping(MappedType.Int32, WireFormat.WireType.Varint)] Int32,
+ [FieldMapping(MappedType.UInt64, WireFormat.WireType.Fixed64)] Fixed64,
+ [FieldMapping(MappedType.UInt32, WireFormat.WireType.Fixed32)] Fixed32,
+ [FieldMapping(MappedType.Boolean, WireFormat.WireType.Varint)] Bool,
+ [FieldMapping(MappedType.String, WireFormat.WireType.LengthDelimited)] String,
+ [FieldMapping(MappedType.Message, WireFormat.WireType.StartGroup)] Group,
+ [FieldMapping(MappedType.Message, WireFormat.WireType.LengthDelimited)] Message,
+ [FieldMapping(MappedType.ByteString, WireFormat.WireType.LengthDelimited)] Bytes,
+ [FieldMapping(MappedType.UInt32, WireFormat.WireType.Varint)] UInt32,
+ [FieldMapping(MappedType.Int32, WireFormat.WireType.Fixed32)] SFixed32,
+ [FieldMapping(MappedType.Int64, WireFormat.WireType.Fixed64)] SFixed64,
+ [FieldMapping(MappedType.Int32, WireFormat.WireType.Varint)] SInt32,
+ [FieldMapping(MappedType.Int64, WireFormat.WireType.Varint)] SInt64,
+ [FieldMapping(MappedType.Enum, WireFormat.WireType.Varint)] Enum
}
}
diff --git a/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs
new file mode 100644
index 0000000000..0aaca88648
--- /dev/null
+++ b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs
@@ -0,0 +1,4 @@
+namespace Google.ProtocolBuffers.Descriptors {
+ class FileDescriptor {
+ }
+}
diff --git a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
index 4e0834f027..df2972f641 100644
--- a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
+++ b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs
@@ -6,5 +6,13 @@ namespace Google.ProtocolBuffers.Descriptors {
public IList Fields;
public DescriptorProtos.MessageOptions Options;
public string FullName;
+
+ internal bool IsExtensionNumber(int fieldNumber) {
+ throw new System.NotImplementedException();
+ }
+
+ internal FieldDescriptor FindFieldByNumber(int fieldNumber) {
+ throw new System.NotImplementedException();
+ }
}
}
diff --git a/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
index d7b239c1cc..cf5220f625 100644
--- a/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
+++ b/csharp/ProtocolBuffers/FieldAccess/FieldAccessorTable.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Text;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.FieldAccess {
diff --git a/csharp/ProtocolBuffers/FieldSet.cs b/csharp/ProtocolBuffers/FieldSet.cs
index 9ab13c6581..4ad9441792 100644
--- a/csharp/ProtocolBuffers/FieldSet.cs
+++ b/csharp/ProtocolBuffers/FieldSet.cs
@@ -104,14 +104,195 @@ namespace Google.ProtocolBuffers {
}
// TODO(jonskeet): Should this be in UnknownFieldSet.Builder really?
+ ///
+ /// Like
+ /// but parses a single field.
+ ///
+ /// The input to read the field from
+ /// The set of unknown fields to add the newly-read field to
+ /// Registry to use when an extension field is encountered
+ /// A builder (???)
+ /// The tag, which should already have been read from the input
+ /// true unless the tag is an end-group tag
internal static bool MergeFieldFrom(CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistry extensionRegistry,
IBuilder builder,
uint tag) {
- throw new NotImplementedException();
+ MessageDescriptor type = builder.DescriptorForType;
+
+ if (type.Options.IsMessageSetWireFormat
+ && tag == WireFormat.MessageSetTag.ItemStart) {
+ MergeMessageSetExtensionFromCodedStream(input, unknownFields, extensionRegistry, builder);
+ return true;
+ }
+
+ WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
+ int fieldNumber = WireFormat.GetTagFieldNumber(tag);
+
+ FieldDescriptor field;
+ IMessage defaultInstance = null;
+
+ if (type.IsExtensionNumber(fieldNumber)) {
+ ExtensionInfo extension = extensionRegistry[type, fieldNumber];
+ if (extension == null) {
+ field = null;
+ } else {
+ field = extension.Descriptor;
+ defaultInstance = extension.DefaultInstance;
+ }
+ } else {
+ field = type.FindFieldByNumber(fieldNumber);
+ }
+
+ // Unknown field or wrong wire type. Skip.
+ if (field == null || wireType != WireFormat.FieldTypeToWireFormatMap[field.FieldType]) {
+ return unknownFields.MergeFieldFrom(tag, input);
+ }
+
+ object value;
+ switch (field.FieldType) {
+ case FieldType.Group:
+ case FieldType.Message: {
+ IBuilder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.CreateBuilderForType();
+ } else {
+ subBuilder = builder.CreateBuilderForField(field);
+ }
+ if (!field.IsRepeated) {
+ subBuilder.MergeFrom((IMessage) builder[field]);
+ }
+ if (field.FieldType == FieldType.Group) {
+ input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
+ } else {
+ input.ReadMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.Build();
+ break;
+ }
+ case FieldType.Enum: {
+ int rawValue = input.ReadEnum();
+ value = field.EnumType.FindValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ unknownFields.MergeVarintField(fieldNumber, (ulong) rawValue);
+ return true;
+ }
+ break;
+ }
+ default:
+ value = input.ReadPrimitiveField(field.FieldType);
+ break;
+ }
+ if (field.IsRepeated) {
+ builder.AddRepeatedField(field, value);
+ } else {
+ builder[field] = value;
+ }
+ return true;
}
+ // TODO(jonskeet): Move to UnknownFieldSet.Builder?
+ ///
+ /// Called by MergeFieldFrom to parse a MessageSet extension.
+ ///
+ private static void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
+ UnknownFieldSet.Builder unknownFields,
+ ExtensionRegistry extensionRegistry,
+ IBuilder builder) {
+ MessageDescriptor type = builder.DescriptorForType;
+
+ // The wire format for MessageSet is:
+ // message MessageSet {
+ // repeated group Item = 1 {
+ // required int32 typeId = 2;
+ // required bytes message = 3;
+ // }
+ // }
+ // "typeId" is the extension's field number. The extension can only be
+ // a message type, where "message" contains the encoded bytes of that
+ // message.
+ //
+ // In practice, we will probably never see a MessageSet item in which
+ // the message appears before the type ID, or where either field does not
+ // appear exactly once. However, in theory such cases are valid, so we
+ // should be prepared to accept them.
+
+ int typeId = 0;
+ ByteString rawBytes = null; // If we encounter "message" before "typeId"
+ IBuilder subBuilder = null;
+ FieldDescriptor field = null;
+
+ while (true) {
+ uint tag = input.ReadTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == WireFormat.MessageSetTag.TypeID) {
+ typeId = input.ReadInt32();
+ // Zero is not a valid type ID.
+ if (typeId != 0) {
+ ExtensionInfo extension = extensionRegistry[type, typeId];
+ if (extension != null) {
+ field = extension.Descriptor;
+ subBuilder = extension.DefaultInstance.CreateBuilderForType();
+ IMessage originalMessage = (IMessage) builder[field];
+ if (originalMessage != null) {
+ subBuilder.MergeFrom(originalMessage);
+ }
+ if (rawBytes != null) {
+ // We already encountered the message. Parse it now.
+ // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
+ // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
+ subBuilder.MergeFrom(rawBytes.CreateCodedInput());
+ rawBytes = null;
+ }
+ } else {
+ // Unknown extension number. If we already saw data, put it
+ // in rawBytes.
+ if (rawBytes != null) {
+ unknownFields.MergeField(typeId,
+ UnknownField.CreateBuilder()
+ .AddLengthDelimited(rawBytes)
+ .Build());
+ rawBytes = null;
+ }
+ }
+ }
+ } else if (tag == WireFormat.MessageSetTag.Message) {
+ if (typeId == 0) {
+ // We haven't seen a type ID yet, so we have to store the raw bytes for now.
+ rawBytes = input.ReadBytes();
+ } else if (subBuilder == null) {
+ // We don't know how to parse this. Ignore it.
+ unknownFields.MergeField(typeId,
+ UnknownField.CreateBuilder()
+ .AddLengthDelimited(input.ReadBytes())
+ .Build());
+ } else {
+ // We already know the type, so we can parse directly from the input
+ // with no copying. Hooray!
+ input.ReadMessage(subBuilder, extensionRegistry);
+ }
+ } else {
+ // Unknown tag. Skip it.
+ if (!input.SkipField(tag)) {
+ break; // end of group
+ }
+ }
+ }
+
+ input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
+
+ if (subBuilder != null) {
+ builder[field] = subBuilder.Build();
+ }
+ }
+
+
///
/// Clears all fields.
///
@@ -120,7 +301,7 @@ namespace Google.ProtocolBuffers {
}
///
- ///
+ /// See
///
///
/// If the field is not set, the behaviour when fetching this property varies by field type:
@@ -172,7 +353,7 @@ namespace Google.ProtocolBuffers {
}
///
- ///
+ /// See
///
internal object this[FieldDescriptor field, int index] {
get {
@@ -196,7 +377,7 @@ namespace Google.ProtocolBuffers {
}
///
- ///
+ /// See
///
///
///
@@ -214,7 +395,7 @@ namespace Google.ProtocolBuffers {
}
///
- ///
+ /// See
///
///
/// Since FieldSet itself does not have any way of knowing about
@@ -259,14 +440,14 @@ namespace Google.ProtocolBuffers {
}
///
- ///
+ /// See
///
public void ClearField(FieldDescriptor field) {
fields.Remove(field);
}
///
- ///
+ /// See
///
public int GetRepeatedFieldCount(FieldDescriptor field) {
if (!field.IsRepeated) {
@@ -276,6 +457,60 @@ namespace Google.ProtocolBuffers {
return ((List