aboutsummaryrefslogtreecommitdiff
path: root/src/ProtocolBuffers
diff options
context:
space:
mode:
Diffstat (limited to 'src/ProtocolBuffers')
-rw-r--r--src/ProtocolBuffers/AbstractMessage.cs32
-rw-r--r--src/ProtocolBuffers/CodedInputStream.cs14
-rw-r--r--src/ProtocolBuffers/CodedOutputStream.cs363
-rw-r--r--src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs99
-rw-r--r--src/ProtocolBuffers/Descriptors/FieldDescriptor.cs4
-rw-r--r--src/ProtocolBuffers/FieldSet.cs34
-rw-r--r--src/ProtocolBuffers/UnknownFieldSet.cs93
-rw-r--r--src/ProtocolBuffers/WireFormat.cs25
8 files changed, 578 insertions, 86 deletions
diff --git a/src/ProtocolBuffers/AbstractMessage.cs b/src/ProtocolBuffers/AbstractMessage.cs
index 9787e159..0a69f294 100644
--- a/src/ProtocolBuffers/AbstractMessage.cs
+++ b/src/ProtocolBuffers/AbstractMessage.cs
@@ -110,8 +110,21 @@ namespace Google.ProtocolBuffers {
if (field.IsRepeated) {
// We know it's an IList<T>, but not the exact type - so
// IEnumerable is the best we can do. (C# generics aren't covariant yet.)
- foreach (object element in (IEnumerable)entry.Value) {
- output.WriteField(field.FieldType, field.FieldNumber, element);
+ IEnumerable valueList = (IEnumerable) entry.Value;
+ if (field.IsPacked) {
+ output.WriteTag(field.FieldNumber, WireFormat.WireType.LengthDelimited);
+ int dataSize = 0;
+ foreach (object element in valueList) {
+ dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+ }
+ output.WriteRawVarint32((uint)dataSize);
+ foreach (object element in valueList) {
+ output.WriteFieldNoTag(field.FieldType, element);
+ }
+ } else {
+ foreach (object element in valueList) {
+ output.WriteField(field.FieldType, field.FieldNumber, element);
+ }
}
} else {
output.WriteField(field.FieldType, field.FieldNumber, entry.Value);
@@ -136,8 +149,19 @@ namespace Google.ProtocolBuffers {
foreach (KeyValuePair<FieldDescriptor, object> entry in AllFields) {
FieldDescriptor field = entry.Key;
if (field.IsRepeated) {
- foreach (object element in (IEnumerable) entry.Value) {
- size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+ IEnumerable valueList = (IEnumerable) entry.Value;
+ if (field.IsPacked) {
+ int dataSize = 0;
+ foreach (object element in valueList) {
+ dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+ }
+ size += dataSize;
+ size += CodedOutputStream.ComputeTagSize(field.FieldNumber);
+ size += CodedOutputStream.ComputeRawVarint32Size((uint)dataSize);
+ } else {
+ foreach (object element in valueList) {
+ size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+ }
}
} else {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, entry.Value);
diff --git a/src/ProtocolBuffers/CodedInputStream.cs b/src/ProtocolBuffers/CodedInputStream.cs
index 78d92519..59d51061 100644
--- a/src/ProtocolBuffers/CodedInputStream.cs
+++ b/src/ProtocolBuffers/CodedInputStream.cs
@@ -609,6 +609,20 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
+ /// Returns whether or not all the data before the limit has been read.
+ /// </summary>
+ /// <returns></returns>
+ public bool ReachedLimit {
+ get {
+ if (currentLimit == int.MaxValue) {
+ return false;
+ }
+ int currentAbsolutePosition = totalBytesRetired + bufferPos;
+ return currentAbsolutePosition >= currentLimit;
+ }
+ }
+
+ /// <summary>
/// Called when buffer is empty to read more bytes from the
/// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
/// either there will be at least one byte in the buffer when it returns
diff --git a/src/ProtocolBuffers/CodedOutputStream.cs b/src/ProtocolBuffers/CodedOutputStream.cs
index df80780a..7cc5ff46 100644
--- a/src/ProtocolBuffers/CodedOutputStream.cs
+++ b/src/ProtocolBuffers/CodedOutputStream.cs
@@ -298,6 +298,156 @@ namespace Google.ProtocolBuffers {
}
}
+ public void WriteFieldNoTag(FieldType fieldType, object value) {
+ switch (fieldType) {
+ case FieldType.Double: WriteDoubleNoTag((double)value); break;
+ case FieldType.Float: WriteFloatNoTag((float)value); break;
+ case FieldType.Int64: WriteInt64NoTag((long)value); break;
+ case FieldType.UInt64: WriteUInt64NoTag((ulong)value); break;
+ case FieldType.Int32: WriteInt32NoTag((int)value); break;
+ case FieldType.Fixed64: WriteFixed64NoTag((ulong)value); break;
+ case FieldType.Fixed32: WriteFixed32NoTag((uint)value); break;
+ case FieldType.Bool: WriteBoolNoTag((bool)value); break;
+ case FieldType.String: WriteStringNoTag((string)value); break;
+ case FieldType.Group: WriteGroupNoTag((IMessage)value); break;
+ case FieldType.Message: WriteMessageNoTag((IMessage)value); break;
+ case FieldType.Bytes: WriteBytesNoTag((ByteString)value); break;
+ case FieldType.UInt32: WriteUInt32NoTag((uint)value); break;
+ case FieldType.SFixed32: WriteSFixed32NoTag((int)value); break;
+ case FieldType.SFixed64: WriteSFixed64NoTag((long)value); break;
+ case FieldType.SInt32: WriteSInt32NoTag((int)value); break;
+ case FieldType.SInt64: WriteSInt64NoTag((long)value); break;
+ case FieldType.Enum: WriteEnumNoTag(((EnumValueDescriptor)value).Number);
+ break;
+ }
+ }
+ #endregion
+
+ #region Writing of values without tags
+ /// <summary>
+ /// Writes a double field value, including tag, to the stream.
+ /// </summary>
+ public void WriteDoubleNoTag(double value) {
+ WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
+ }
+
+ /// <summary>
+ /// Writes a float field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteFloatNoTag(float value) {
+ // TODO(jonskeet): Test this on different endiannesses
+ byte[] rawBytes = BitConverter.GetBytes(value);
+ uint asInteger = BitConverter.ToUInt32(rawBytes, 0);
+ WriteRawLittleEndian32(asInteger);
+ }
+
+ /// <summary>
+ /// Writes a uint64 field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteUInt64NoTag(ulong value) {
+ WriteRawVarint64(value);
+ }
+
+ /// <summary>
+ /// Writes an int64 field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteInt64NoTag(long value) {
+ WriteRawVarint64((ulong)value);
+ }
+
+ /// <summary>
+ /// Writes an int32 field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteInt32NoTag(int value) {
+ if (value >= 0) {
+ WriteRawVarint32((uint)value);
+ } else {
+ // Must sign-extend.
+ WriteRawVarint64((ulong)value);
+ }
+ }
+
+ /// <summary>
+ /// Writes a fixed64 field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteFixed64NoTag(ulong value) {
+ WriteRawLittleEndian64(value);
+ }
+
+ /// <summary>
+ /// Writes a fixed32 field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteFixed32NoTag(uint value) {
+ WriteRawLittleEndian32(value);
+ }
+
+ /// <summary>
+ /// Writes a bool field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteBoolNoTag(bool value) {
+ WriteRawByte(value ? (byte)1 : (byte)0);
+ }
+
+ /// <summary>
+ /// Writes a string field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteStringNoTag(string value) {
+ // Optimise the case where we have enough space to write
+ // the string directly to the buffer, which should be common.
+ int length = Encoding.UTF8.GetByteCount(value);
+ WriteRawVarint32((uint)length);
+ if (limit - position >= length) {
+ Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
+ position += length;
+ } else {
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ WriteRawBytes(bytes);
+ }
+ }
+
+ /// <summary>
+ /// Writes a group field value, without a tag, to the stream.
+ /// </summary>
+ public void WriteGroupNoTag(IMessage value) {
+ value.WriteTo(this);
+ }
+
+ public void WriteMessageNoTag(IMessage value) {
+ WriteRawVarint32((uint)value.SerializedSize);
+ value.WriteTo(this);
+ }
+
+ public void WriteBytesNoTag(ByteString value) {
+ // TODO(jonskeet): Optimise this! (No need to copy the bytes twice.)
+ byte[] bytes = value.ToByteArray();
+ WriteRawVarint32((uint)bytes.Length);
+ WriteRawBytes(bytes);
+ }
+
+ public void WriteUInt32NoTag(uint value) {
+ WriteRawVarint32(value);
+ }
+
+ public void WriteEnumNoTag(int value) {
+ WriteRawVarint32((uint)value);
+ }
+
+ public void WriteSFixed32NoTag(int value) {
+ WriteRawLittleEndian32((uint)value);
+ }
+
+ public void WriteSFixed64NoTag(long value) {
+ WriteRawLittleEndian64((ulong)value);
+ }
+
+ public void WriteSInt32NoTag(int value) {
+ WriteRawVarint32(EncodeZigZag32(value));
+ }
+
+ public void WriteSInt64NoTag(long value) {
+ WriteRawVarint64(EncodeZigZag64(value));
+ }
+
#endregion
#region Underlying writing primitives
@@ -583,8 +733,7 @@ namespace Google.ProtocolBuffers {
/// sint32 field, including the tag.
/// </summary>
public static int ComputeSInt32Size(int fieldNumber, int value) {
- return ComputeTagSize(fieldNumber) +
- ComputeRawVarint32Size(EncodeZigZag32(value));
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint32Size(EncodeZigZag32(value));
}
/// <summary>
@@ -592,8 +741,169 @@ namespace Google.ProtocolBuffers {
/// sint64 field, including the tag.
/// </summary>
public static int ComputeSInt64Size(int fieldNumber, long value) {
- return ComputeTagSize(fieldNumber) +
- ComputeRawVarint64Size(EncodeZigZag64(value));
+ return ComputeTagSize(fieldNumber) + ComputeRawVarint64Size(EncodeZigZag64(value));
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// double field, including the tag.
+ /// </summary>
+ public static int ComputeDoubleSizeNoTag(double value) {
+ return LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// float field, including the tag.
+ /// </summary>
+ public static int ComputeFloatSizeNoTag(float value) {
+ return LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// uint64 field, including the tag.
+ /// </summary>
+ public static int ComputeUInt64SizeNoTag(ulong value) {
+ return ComputeRawVarint64Size(value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// int64 field, including the tag.
+ /// </summary>
+ public static int ComputeInt64SizeNoTag(long value) {
+ return ComputeRawVarint64Size((ulong)value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// int32 field, including the tag.
+ /// </summary>
+ public static int ComputeInt32SizeNoTag(int value) {
+ if (value >= 0) {
+ return ComputeRawVarint32Size((uint)value);
+ } else {
+ // Must sign-extend.
+ return 10;
+ }
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// fixed64 field, including the tag.
+ /// </summary>
+ public static int ComputeFixed64SizeNoTag(ulong value) {
+ return LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// fixed32 field, including the tag.
+ /// </summary>
+ public static int ComputeFixed32SizeNoTag(uint value) {
+ return LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// bool field, including the tag.
+ /// </summary>
+ public static int ComputeBoolSizeNoTag(bool value) {
+ return 1;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// string field, including the tag.
+ /// </summary>
+ public static int ComputeStringSizeNoTag(String value) {
+ int byteArraySize = Encoding.UTF8.GetByteCount(value);
+ return ComputeRawVarint32Size((uint)byteArraySize) +
+ byteArraySize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// group field, including the tag.
+ /// </summary>
+ public static int ComputeGroupSizeNoTag(IMessage value) {
+ return value.SerializedSize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// group field represented by an UnknownFieldSet, including the tag.
+ /// </summary>
+ public static int ComputeUnknownGroupSizeNoTag(UnknownFieldSet value) {
+ return value.SerializedSize;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// embedded message field, including the tag.
+ /// </summary>
+ public static int ComputeMessageSizeNoTag(IMessage value) {
+ int size = value.SerializedSize;
+ return ComputeRawVarint32Size((uint)size) + size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// bytes field, including the tag.
+ /// </summary>
+ public static int ComputeBytesSizeNoTag(ByteString value) {
+ return ComputeRawVarint32Size((uint)value.Length) +
+ value.Length;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// uint32 field, including the tag.
+ /// </summary>
+ public static int ComputeUInt32SizeNoTag(uint value) {
+ return ComputeRawVarint32Size(value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// enum field, including the tag. The caller is responsible for
+ /// converting the enum value to its numeric value.
+ /// </summary>
+ public static int ComputeEnumSizeNoTag(int value) {
+ return ComputeRawVarint32Size((uint)value);
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sfixed32 field, including the tag.
+ /// </summary>
+ public static int ComputeSFixed32SizeNoTag(int value) {
+ return LittleEndian32Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sfixed64 field, including the tag.
+ /// </summary>
+ public static int ComputeSFixed64SizeNoTag(long value) {
+ return LittleEndian64Size;
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sint32 field, including the tag.
+ /// </summary>
+ public static int ComputeSInt32SizeNoTag(int value) {
+ return ComputeRawVarint32Size(EncodeZigZag32(value));
+ }
+
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode an
+ /// sint64 field, including the tag.
+ /// </summary>
+ public static int ComputeSInt64SizeNoTag(long value) {
+ return ComputeRawVarint64Size(EncodeZigZag64(value));
}
/*
@@ -650,18 +960,10 @@ namespace Google.ProtocolBuffers {
return 10;
}
-
- /*
- * Compute the number of bytes that would be needed to encode a
- * field of arbitrary type, including tag, to the stream.
- *
- * @param type The field's type.
- * @param number The field's number.
- * @param value Object representing the field's value. Must be of the exact
- * type which would be returned by
- * {@link Message#getField(FieldDescriptor)} for
- * this field.
- */
+ /// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// field of arbitrary type, including the tag, to the stream.
+ /// </summary>
public static int ComputeFieldSize(FieldType fieldType, int fieldNumber, Object value) {
switch (fieldType) {
case FieldType.Double: return ComputeDoubleSize(fieldNumber, (double)value);
@@ -688,6 +990,35 @@ namespace Google.ProtocolBuffers {
}
/// <summary>
+ /// Compute the number of bytes that would be needed to encode a
+ /// field of arbitrary type, excluding the tag, to the stream.
+ /// </summary>
+ public static int ComputeFieldSizeNoTag(FieldType fieldType, Object value) {
+ switch (fieldType) {
+ case FieldType.Double: return ComputeDoubleSizeNoTag((double)value);
+ case FieldType.Float: return ComputeFloatSizeNoTag((float)value);
+ case FieldType.Int64: return ComputeInt64SizeNoTag((long)value);
+ case FieldType.UInt64: return ComputeUInt64SizeNoTag((ulong)value);
+ case FieldType.Int32: return ComputeInt32SizeNoTag((int)value);
+ case FieldType.Fixed64: return ComputeFixed64SizeNoTag((ulong)value);
+ case FieldType.Fixed32: return ComputeFixed32SizeNoTag((uint)value);
+ case FieldType.Bool: return ComputeBoolSizeNoTag((bool)value);
+ case FieldType.String: return ComputeStringSizeNoTag((string)value);
+ case FieldType.Group: return ComputeGroupSizeNoTag((IMessage)value);
+ case FieldType.Message: return ComputeMessageSizeNoTag((IMessage)value);
+ case FieldType.Bytes: return ComputeBytesSizeNoTag((ByteString)value);
+ case FieldType.UInt32: return ComputeUInt32SizeNoTag((uint)value);
+ case FieldType.SFixed32: return ComputeSFixed32SizeNoTag((int)value);
+ case FieldType.SFixed64: return ComputeSFixed64SizeNoTag((long)value);
+ case FieldType.SInt32: return ComputeSInt32SizeNoTag((int)value);
+ case FieldType.SInt64: return ComputeSInt64SizeNoTag((long)value);
+ case FieldType.Enum: return ComputeEnumSizeNoTag(((EnumValueDescriptor)value).Number);
+ default:
+ throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
+ }
+ }
+
+ /// <summary>
/// Compute the number of bytes that would be needed to encode a tag.
/// </summary>
public static int ComputeTagSize(int fieldNumber) {
diff --git a/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs b/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
index 4206f261..1fe7928c 100644
--- a/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
+++ b/src/ProtocolBuffers/DescriptorProtos/DescriptorProtoFile.cs
@@ -70,27 +70,27 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
"AioJCOgHEICAgIACIogBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdlX3Nl" +
"dF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9v" +
"cHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRP" +
- "cHRpb24qCQjoBxCAgICAAiLVAQoMRmllbGRPcHRpb25zEjIKBWN0eXBlGAEg" +
- "ASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZRIcChRl" +
- "eHBlcmltZW50YWxfbWFwX2tleRgJIAEoCRJDChR1bmludGVycHJldGVkX29w" +
- "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w" +
- "dGlvbiIjCgVDVHlwZRIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIqCQjo" +
- "BxCAgICAAiJdCgtFbnVtT3B0aW9ucxJDChR1bmludGVycHJldGVkX29wdGlv" +
- "bhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlv" +
- "bioJCOgHEICAgIACImIKEEVudW1WYWx1ZU9wdGlvbnMSQwoUdW5pbnRlcnBy" +
- "ZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJw" +
- "cmV0ZWRPcHRpb24qCQjoBxCAgICAAiJgCg5TZXJ2aWNlT3B0aW9ucxJDChR1" +
- "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu" +
- "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACIl8KDU1ldGhvZE9wdGlv" +
- "bnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnBy" +
- "b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKFAgoTVW5p" +
- "bnRlcnByZXRlZE9wdGlvbhI7CgRuYW1lGAIgAygLMi0uZ29vZ2xlLnByb3Rv" +
- "YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24uTmFtZVBhcnQSGAoQaWRlbnRpZmll" +
- "cl92YWx1ZRgDIAEoCRIaChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKAQSGgoS" +
- "bmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDEhQKDGRvdWJsZV92YWx1ZRgGIAEo" +
- "ARIUCgxzdHJpbmdfdmFsdWUYByABKAwaMwoITmFtZVBhcnQSEQoJbmFtZV9w" +
- "YXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCEIpChNjb20uZ29vZ2xl" +
- "LnByb3RvYnVmQhBEZXNjcmlwdG9yUHJvdG9zSAE="),
+ "cHRpb24qCQjoBxCAgICAAiLlAQoMRmllbGRPcHRpb25zEjIKBWN0eXBlGAEg" +
+ "ASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlwZRIOCgZw" +
+ "YWNrZWQYAiABKAgSHAoUZXhwZXJpbWVudGFsX21hcF9rZXkYCSABKAkSQwoU" +
+ "dW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVm" +
+ "LlVuaW50ZXJwcmV0ZWRPcHRpb24iIwoFQ1R5cGUSCAoEQ09SRBABEhAKDFNU" +
+ "UklOR19QSUVDRRACKgkI6AcQgICAgAIiXQoLRW51bU9wdGlvbnMSQwoUdW5p" +
+ "bnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVu" +
+ "aW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiJiChBFbnVtVmFsdWVPcHRp" +
+ "b25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w" +
+ "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiYAoOU2Vy" +
+ "dmljZU9wdGlvbnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQu" +
+ "Z29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICA" +
+ "AiJfCg1NZXRob2RPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcH" +
+ "IAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI" +
+ "6AcQgICAgAIihQIKE1VuaW50ZXJwcmV0ZWRPcHRpb24SOwoEbmFtZRgCIAMo" +
+ "CzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uLk5hbWVQ" +
+ "YXJ0EhgKEGlkZW50aWZpZXJfdmFsdWUYAyABKAkSGgoScG9zaXRpdmVfaW50" +
+ "X3ZhbHVlGAQgASgEEhoKEm5lZ2F0aXZlX2ludF92YWx1ZRgFIAEoAxIUCgxk" +
+ "b3VibGVfdmFsdWUYBiABKAESFAoMc3RyaW5nX3ZhbHVlGAcgASgMGjMKCE5h" +
+ "bWVQYXJ0EhEKCW5hbWVfcGFydBgBIAIoCRIUCgxpc19leHRlbnNpb24YAiAC" +
+ "KAhCKQoTY29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRvclByb3Rvc0gB"),
new pbd::FileDescriptor[] {
});
#endregion
@@ -155,7 +155,7 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
= Descriptor.MessageTypes[10];
internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions.Builder> internal__static_google_protobuf_FieldOptions__FieldAccessorTable
= new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions, global::Google.ProtocolBuffers.DescriptorProtos.FieldOptions.Builder>(internal__static_google_protobuf_FieldOptions__Descriptor,
- new string[] { "Ctype", "ExperimentalMapKey", "UninterpretedOption", });
+ new string[] { "Ctype", "Packed", "ExperimentalMapKey", "UninterpretedOption", });
internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_EnumOptions__Descriptor
= Descriptor.MessageTypes[11];
internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions, global::Google.ProtocolBuffers.DescriptorProtos.EnumOptions.Builder> internal__static_google_protobuf_EnumOptions__FieldAccessorTable
@@ -541,8 +541,10 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
if (HasPackage) {
output.WriteString(2, Package);
}
- foreach (string element in DependencyList) {
- output.WriteString(3, element);
+ if (dependency_.Count > 0) {
+ foreach (string element in dependency_) {
+ output.WriteString(3, element);
+ }
}
foreach (global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto element in MessageTypeList) {
output.WriteMessage(4, element);
@@ -575,8 +577,13 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
if (HasPackage) {
size += pb::CodedOutputStream.ComputeStringSize(2, Package);
}
- foreach (string element in DependencyList) {
- size += pb::CodedOutputStream.ComputeStringSize(3, element);
+ {
+ int dataSize = 0;
+ foreach (string element in DependencyList) {
+ dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * dependency_.Count;
}
foreach (global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProto element in MessageTypeList) {
size += pb::CodedOutputStream.ComputeMessageSize(4, element);
@@ -4413,6 +4420,15 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
get { return ctype_; }
}
+ private bool hasPacked;
+ private bool packed_ = false;
+ public bool HasPacked {
+ get { return hasPacked; }
+ }
+ public bool Packed {
+ get { return packed_; }
+ }
+
private bool hasExperimentalMapKey;
private string experimentalMapKey_ = "";
public bool HasExperimentalMapKey {
@@ -4448,6 +4464,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
if (HasCtype) {
output.WriteEnum(1, (int) Ctype);
}
+ if (HasPacked) {
+ output.WriteBool(2, Packed);
+ }
if (HasExperimentalMapKey) {
output.WriteString(9, ExperimentalMapKey);
}
@@ -4468,6 +4487,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
if (HasCtype) {
size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Ctype);
}
+ if (HasPacked) {
+ size += pb::CodedOutputStream.ComputeBoolSize(2, Packed);
+ }
if (HasExperimentalMapKey) {
size += pb::CodedOutputStream.ComputeStringSize(9, ExperimentalMapKey);
}
@@ -4561,6 +4583,9 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
if (other.HasCtype) {
Ctype = other.Ctype;
}
+ if (other.HasPacked) {
+ Packed = other.Packed;
+ }
if (other.HasExperimentalMapKey) {
ExperimentalMapKey = other.ExperimentalMapKey;
}
@@ -4601,6 +4626,10 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
}
break;
}
+ case 16: {
+ Packed = input.ReadBool();
+ break;
+ }
case 74: {
ExperimentalMapKey = input.ReadString();
break;
@@ -4634,6 +4663,24 @@ namespace Google.ProtocolBuffers.DescriptorProtos {
return this;
}
+ public bool HasPacked {
+ get { return result.HasPacked; }
+ }
+ public bool Packed {
+ get { return result.Packed; }
+ set { SetPacked(value); }
+ }
+ public Builder SetPacked(bool value) {
+ result.hasPacked = true;
+ result.packed_ = value;
+ return this;
+ }
+ public Builder ClearPacked() {
+ result.hasPacked = false;
+ result.packed_ = false;
+ return this;
+ }
+
public bool HasExperimentalMapKey {
get { return result.HasExperimentalMapKey; }
}
diff --git a/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
index 0d0fad76..eca3d6d1 100644
--- a/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
+++ b/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
@@ -176,6 +176,10 @@ namespace Google.ProtocolBuffers.Descriptors {
get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
}
+ public bool IsPacked {
+ get { return Proto.Options.Packed; }
+ }
+
/// <valule>
/// Indicates whether or not the field had an explicitly-defined default value.
/// </value>
diff --git a/src/ProtocolBuffers/FieldSet.cs b/src/ProtocolBuffers/FieldSet.cs
index bc2e2e70..913dede2 100644
--- a/src/ProtocolBuffers/FieldSet.cs
+++ b/src/ProtocolBuffers/FieldSet.cs
@@ -368,8 +368,23 @@ namespace Google.ProtocolBuffers {
output.WriteMessageSetExtension(field.FieldNumber, (IMessage) value);
} else {
if (field.IsRepeated) {
- foreach (object element in (IEnumerable) value) {
- output.WriteField(field.FieldType, field.FieldNumber, element);
+ IEnumerable valueList = (IEnumerable) value;
+ if (field.IsPacked) {
+ output.WriteTag(field.FieldNumber, WireFormat.WireType.LengthDelimited);
+ // Compute the total data size so the length can be written.
+ int dataSize = 0;
+ foreach (object element in valueList) {
+ dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+ }
+ output.WriteRawVarint32((uint)dataSize);
+ // Write the data itself, without any tags.
+ foreach (object element in valueList) {
+ output.WriteFieldNoTag(field.FieldType, element);
+ }
+ } else {
+ foreach (object element in valueList) {
+ output.WriteField(field.FieldType, field.FieldNumber, element);
+ }
}
} else {
output.WriteField(field.FieldType, field.FieldNumber, value);
@@ -389,11 +404,20 @@ namespace Google.ProtocolBuffers {
object value = entry.Value;
if (field.IsExtension && field.ContainingType.Options.MessageSetWireFormat) {
- size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage) value);
+ size += CodedOutputStream.ComputeMessageSetExtensionSize(field.FieldNumber, (IMessage)value);
} else {
if (field.IsRepeated) {
- foreach (object element in (IEnumerable) value) {
- size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+ IEnumerable valueList = (IEnumerable)value;
+ if (field.IsPacked) {
+ int dataSize = 0;
+ foreach (object element in valueList) {
+ dataSize += CodedOutputStream.ComputeFieldSizeNoTag(field.FieldType, element);
+ }
+ size += dataSize + CodedOutputStream.ComputeTagSize(field.FieldNumber) + CodedOutputStream.ComputeRawVarint32Size((uint)dataSize);
+ } else {
+ foreach (object element in valueList) {
+ size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, element);
+ }
}
} else {
size += CodedOutputStream.ComputeFieldSize(field.FieldType, field.FieldNumber, value);
diff --git a/src/ProtocolBuffers/UnknownFieldSet.cs b/src/ProtocolBuffers/UnknownFieldSet.cs
index ecae53ce..aa371fad 100644
--- a/src/ProtocolBuffers/UnknownFieldSet.cs
+++ b/src/ProtocolBuffers/UnknownFieldSet.cs
@@ -497,50 +497,73 @@ namespace Google.ProtocolBuffers {
}
// Unknown field or wrong wire type. Skip.
- if (field == null || wireType != WireFormat.GetWireType(field.FieldType)) {
+ if (field == null || wireType != WireFormat.GetWireType(field)) {
return MergeFieldFrom(tag, input);
}
- object value;
- switch (field.FieldType) {
- case FieldType.Group:
- case FieldType.Message: {
- IBuilder subBuilder;
- if (defaultFieldInstance != null) {
- subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
- } else {
- subBuilder = builder.CreateBuilderForField(field);
- }
- if (!field.IsRepeated) {
- subBuilder.WeakMergeFrom((IMessage)builder[field]);
- }
- if (field.FieldType == FieldType.Group) {
- input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
- } else {
- input.ReadMessage(subBuilder, extensionRegistry);
- }
- value = subBuilder.WeakBuild();
- break;
- }
- case FieldType.Enum: {
+ if (field.IsPacked) {
+ int length = (int)input.ReadRawVarint32();
+ int limit = input.PushLimit(length);
+ if (field.FieldType == FieldType.Enum) {
+ while (!input.ReachedLimit) {
int rawValue = input.ReadEnum();
- value = field.EnumType.FindValueByNumber(rawValue);
- // If the number isn't recognized as a valid value for this enum,
- // drop it.
+ object value = field.EnumType.FindValueByNumber(rawValue);
if (value == null) {
- MergeVarintField(fieldNumber, (ulong)rawValue);
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
return true;
}
- break;
+ builder.WeakAddRepeatedField(field, value);
}
- default:
- value = input.ReadPrimitiveField(field.FieldType);
- break;
- }
- if (field.IsRepeated) {
- builder.WeakAddRepeatedField(field, value);
+ } else {
+ while (!input.ReachedLimit) {
+ Object value = input.ReadPrimitiveField(field.FieldType);
+ builder.WeakAddRepeatedField(field, value);
+ }
+ }
+ input.PopLimit(limit);
} else {
- builder[field] = value;
+ object value;
+ switch (field.FieldType) {
+ case FieldType.Group:
+ case FieldType.Message: {
+ IBuilder subBuilder;
+ if (defaultFieldInstance != null) {
+ subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
+ } else {
+ subBuilder = builder.CreateBuilderForField(field);
+ }
+ if (!field.IsRepeated) {
+ subBuilder.WeakMergeFrom((IMessage)builder[field]);
+ }
+ if (field.FieldType == FieldType.Group) {
+ input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
+ } else {
+ input.ReadMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.WeakBuild();
+ 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) {
+ MergeVarintField(fieldNumber, (ulong)rawValue);
+ return true;
+ }
+ break;
+ }
+ default:
+ value = input.ReadPrimitiveField(field.FieldType);
+ break;
+ }
+ if (field.IsRepeated) {
+ builder.WeakAddRepeatedField(field, value);
+ } else {
+ builder[field] = value;
+ }
}
return true;
}
diff --git a/src/ProtocolBuffers/WireFormat.cs b/src/ProtocolBuffers/WireFormat.cs
index abf47169..2bd0a5aa 100644
--- a/src/ProtocolBuffers/WireFormat.cs
+++ b/src/ProtocolBuffers/WireFormat.cs
@@ -46,6 +46,19 @@ namespace Google.ProtocolBuffers {
/// </para>
/// </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
+
+
public enum WireType : uint {
Varint = 0,
Fixed64 = 1,
@@ -93,6 +106,18 @@ namespace Google.ProtocolBuffers {
return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
}
+ public static uint MakeTag(FieldDescriptor field) {
+ return MakeTag(field.FieldNumber, GetWireType(field));
+ }
+
+ /// <summary>
+ /// Returns the wire type for the given field descriptor. This differs
+ /// from GetWireType(FieldType) for packed repeated fields.
+ /// </summary>
+ internal static WireType GetWireType(FieldDescriptor descriptor) {
+ return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
+ }
+
/// <summary>
/// Converts a field type to its wire type. Done with a switch for the sake
/// of speed - this is significantly faster than a dictionary lookup.