Support packed primitive types

This commit is contained in:
Jon Skeet 2009-02-18 16:06:22 +00:00
parent 0ca3fecfaf
commit 25a28580a6
26 changed files with 3492 additions and 877 deletions

Binary file not shown.

View File

@ -252,6 +252,8 @@ message FileOptions {
}
optional OptimizeMode optimize_for = 9 [default=CODE_SIZE];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@ -298,6 +300,11 @@ message FieldOptions {
STRING_PIECE = 2;
}
// The packed option can be enabled for repeated primitive fields to enable
// a more efficient representation on the wire. Rather than repeatedly
// writing the tag and type for each element, the entire array is encoded as
// a single length-delimited blob.
optional bool packed = 2;
// EXPERIMENTAL. DO NOT USE.
// For "map" fields, the name of the field in the enclosed type that

View File

@ -458,6 +458,44 @@ message TestExtremeDefaultValues {
optional string utf8_string = 6 [default = "\341\210\264"];
}
message TestPackedTypes {
repeated int32 packed_int32 = 90 [packed = true];
repeated int64 packed_int64 = 91 [packed = true];
repeated uint32 packed_uint32 = 92 [packed = true];
repeated uint64 packed_uint64 = 93 [packed = true];
repeated sint32 packed_sint32 = 94 [packed = true];
repeated sint64 packed_sint64 = 95 [packed = true];
repeated fixed32 packed_fixed32 = 96 [packed = true];
repeated fixed64 packed_fixed64 = 97 [packed = true];
repeated sfixed32 packed_sfixed32 = 98 [packed = true];
repeated sfixed64 packed_sfixed64 = 99 [packed = true];
repeated float packed_float = 100 [packed = true];
repeated double packed_double = 101 [packed = true];
repeated bool packed_bool = 102 [packed = true];
repeated ForeignEnum packed_enum = 103 [packed = true];
}
message TestPackedExtensions {
extensions 1 to max;
}
extend TestPackedExtensions {
repeated int32 packed_int32_extension = 90 [packed = true];
repeated int64 packed_int64_extension = 91 [packed = true];
repeated uint32 packed_uint32_extension = 92 [packed = true];
repeated uint64 packed_uint64_extension = 93 [packed = true];
repeated sint32 packed_sint32_extension = 94 [packed = true];
repeated sint64 packed_sint64_extension = 95 [packed = true];
repeated fixed32 packed_fixed32_extension = 96 [packed = true];
repeated fixed64 packed_fixed64_extension = 97 [packed = true];
repeated sfixed32 packed_sfixed32_extension = 98 [packed = true];
repeated sfixed64 packed_sfixed64_extension = 99 [packed = true];
repeated float packed_float_extension = 100 [packed = true];
repeated double packed_double_extension = 101 [packed = true];
repeated bool packed_bool_extension = 102 [packed = true];
repeated ForeignEnum packed_enum_extension = 103 [packed = true];
}
// Test that RPC services work.
message FooRequest {}
message FooResponse {}

View File

@ -523,8 +523,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField4) {
output.WriteString(4, Field4);
}
foreach (ulong element in Field5List) {
output.WriteFixed64(5, element);
if (field5_.Count > 0) {
foreach (ulong element in field5_) {
output.WriteFixed64(5, element);
}
}
if (HasField6) {
output.WriteInt32(6, Field6);
@ -677,8 +679,11 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField4) {
size += pb::CodedOutputStream.ComputeStringSize(4, Field4);
}
foreach (ulong element in Field5List) {
size += pb::CodedOutputStream.ComputeFixed64Size(5, element);
{
int dataSize = 0;
dataSize = 8 * field5_.Count;
size += dataSize;
size += 1 * field5_.Count;
}
if (HasField59) {
size += pb::CodedOutputStream.ComputeBoolSize(59, Field59);
@ -3116,8 +3121,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField13) {
output.WriteString(13, Field13);
}
foreach (string element in Field14List) {
output.WriteString(14, element);
if (field14_.Count > 0) {
foreach (string element in field14_) {
output.WriteString(14, element);
}
}
if (HasField15) {
output.WriteUInt64(15, Field15);
@ -3128,8 +3135,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField20) {
output.WriteInt32(20, Field20);
}
foreach (string element in Field22List) {
output.WriteString(22, element);
if (field22_.Count > 0) {
foreach (string element in field22_) {
output.WriteString(22, element);
}
}
if (HasField24) {
output.WriteString(24, Field24);
@ -3149,8 +3158,10 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField31) {
output.WriteMessage(31, Field31);
}
foreach (int element in Field73List) {
output.WriteInt32(73, element);
if (field73_.Count > 0) {
foreach (int element in field73_) {
output.WriteInt32(73, element);
}
}
UnknownFields.WriteTo(output);
}
@ -3174,8 +3185,13 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField13) {
size += pb::CodedOutputStream.ComputeStringSize(13, Field13);
}
foreach (string element in Field14List) {
size += pb::CodedOutputStream.ComputeStringSize(14, element);
{
int dataSize = 0;
foreach (string element in Field14List) {
dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
}
size += dataSize;
size += 1 * field14_.Count;
}
if (HasField15) {
size += pb::CodedOutputStream.ComputeUInt64Size(15, Field15);
@ -3195,11 +3211,21 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField16) {
size += pb::CodedOutputStream.ComputeStringSize(16, Field16);
}
foreach (string element in Field22List) {
size += pb::CodedOutputStream.ComputeStringSize(22, element);
{
int dataSize = 0;
foreach (string element in Field22List) {
dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
}
size += dataSize;
size += 2 * field22_.Count;
}
foreach (int element in Field73List) {
size += pb::CodedOutputStream.ComputeInt32Size(73, element);
{
int dataSize = 0;
foreach (int element in Field73List) {
dataSize += pb::CodedOutputStream.ComputeInt32SizeNoTag(element);
}
size += dataSize;
size += 2 * field73_.Count;
}
if (HasField20) {
size += pb::CodedOutputStream.ComputeInt32Size(20, Field20);
@ -4110,17 +4136,23 @@ namespace Google.ProtocolBuffers.ProtoBench {
if (HasField109) {
output.WriteInt32(109, Field109);
}
foreach (string element in Field127List) {
output.WriteString(127, element);
if (field127_.Count > 0) {
foreach (string element in field127_) {
output.WriteString(127, element);
}
}
foreach (string element in Field128List) {
output.WriteString(128, element);
if (field128_.Count > 0) {
foreach (string element in field128_) {
output.WriteString(128, element);
}
}
if (HasField129) {
output.WriteInt32(129, Field129);
}
foreach (long element in Field130List) {
output.WriteInt64(130, element);
if (field130_.Count > 0) {
foreach (long element in field130_) {
output.WriteInt64(130, element);
}
}
if (HasField131) {
output.WriteInt64(131, Field131);
@ -4240,20 +4272,35 @@ namespace Google.ProtocolBuffers.ProtoBench {
foreach (global::Google.ProtocolBuffers.ProtoBench.SpeedMessage3.Types.Group1 element in Group1List) {
size += pb::CodedOutputStream.ComputeGroupSize(10, element);
}
foreach (string element in Field128List) {
size += pb::CodedOutputStream.ComputeStringSize(128, element);
{
int dataSize = 0;
foreach (string element in Field128List) {
dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
}
size += dataSize;
size += 2 * field128_.Count;
}
if (HasField131) {
size += pb::CodedOutputStream.ComputeInt64Size(131, Field131);
}
foreach (string element in Field127List) {
size += pb::CodedOutputStream.ComputeStringSize(127, element);
{
int dataSize = 0;
foreach (string element in Field127List) {
dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
}
size += dataSize;
size += 2 * field127_.Count;
}
if (HasField129) {
size += pb::CodedOutputStream.ComputeInt32Size(129, Field129);
}
foreach (long element in Field130List) {
size += pb::CodedOutputStream.ComputeInt64Size(130, element);
{
int dataSize = 0;
foreach (long element in Field130List) {
dataSize += pb::CodedOutputStream.ComputeInt64SizeNoTag(element);
}
size += dataSize;
size += 2 * field130_.Count;
}
if (HasField205) {
size += pb::CodedOutputStream.ComputeBoolSize(205, Field205);

View File

@ -97,6 +97,45 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
}
/// <summary>
/// For encodings with fixed sizes, returns that size in bytes. Otherwise
/// returns -1. TODO(jonskeet): Make this less ugly.
/// </summary>
protected int FixedSize {
get {
switch (Descriptor.FieldType) {
case FieldType.UInt32:
case FieldType.UInt64:
case FieldType.Int32:
case FieldType.Int64:
case FieldType.SInt32:
case FieldType.SInt64:
case FieldType.Enum:
case FieldType.Bytes:
case FieldType.String:
case FieldType.Message:
case FieldType.Group:
return -1;
case FieldType.Float:
return WireFormat.FloatSize;
case FieldType.SFixed32:
return WireFormat.SFixed32Size;
case FieldType.Fixed32:
return WireFormat.Fixed32Size;
case FieldType.Double:
return WireFormat.DoubleSize;
case FieldType.SFixed64:
return WireFormat.SFixed64Size;
case FieldType.Fixed64:
return WireFormat.Fixed64Size;
case FieldType.Bool:
return WireFormat.BoolSize;
default:
throw new InvalidOperationException("Invalid field descriptor type");
}
}
}
protected bool IsNullableType {
get {
switch (Descriptor.FieldType) {

View File

@ -391,7 +391,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(" break;");
writer.WriteLine("}");
foreach (FieldDescriptor field in sortedFields) {
uint tag = WireFormat.MakeTag(field.FieldNumber, WireFormat.GetWireType(field.FieldType));
uint tag = WireFormat.MakeTag(field);
writer.WriteLine("case {0}: {{", tag);
writer.Indent();
SourceGenerators.CreateFieldGenerator(field).GenerateParsingCode(writer);

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
@ -11,6 +9,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateMembers(TextGenerator writer) {
if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
}
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@ -66,6 +67,15 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateParsingCode(TextGenerator writer) {
// If packed, set up the while loop
if (Descriptor.IsPacked) {
writer.WriteLine("int length = input.ReadInt32();");
writer.WriteLine("int oldLimit = input.PushLimit(length);");
writer.WriteLine("while (!input.ReachedLimit) {");
writer.Indent();
}
// Read and store the enum
// TODO(jonskeet): Make a more efficient way of doing this
writer.WriteLine("int rawValue = input.ReadEnum();");
writer.WriteLine("if (!global::System.Enum.IsDefined(typeof({0}), rawValue)) {{", TypeName);
@ -73,17 +83,56 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("} else {");
writer.WriteLine(" Add{0}(({1}) rawValue);", PropertyName, TypeName);
writer.WriteLine("}");
if (Descriptor.IsPacked) {
writer.Outdent();
writer.WriteLine("}");
writer.WriteLine("input.PopLimit(oldLimit);");
}
}
public void GenerateSerializationCode(TextGenerator writer) {
writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
writer.WriteLine(" output.WriteEnum({0}, (int) element);", Number);
writer.WriteLine("if ({0}_.Count > 0) {{", Name);
writer.Indent();
if (Descriptor.IsPacked) {
writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
writer.WriteLine("foreach (int element in {0}_) {{", Name);
writer.WriteLine(" output.WriteEnumNoTag(element);");
writer.WriteLine("}");
} else {
writer.WriteLine("foreach (int element in {0}_) {{", Name);
writer.WriteLine(" output.WriteEnum({0}, element);", Number);
writer.WriteLine("}");
}
writer.Outdent();
writer.WriteLine("}");
}
public void GenerateSerializedSizeCode(TextGenerator writer) {
writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
writer.WriteLine(" size += pb::CodedOutputStream.ComputeEnumSize({0}, (int) element);", Number);
writer.WriteLine("{");
writer.Indent();
writer.WriteLine("int dataSize = 0;");
writer.WriteLine("if ({0}_.Count > 0) {{", Name);
writer.Indent();
writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
writer.WriteLine(" dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);");
writer.WriteLine("}");
writer.WriteLine("size += dataSize;");
int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
if (Descriptor.IsPacked) {
writer.WriteLine("size += {0};", tagSize);
writer.WriteLine("size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);");
} else {
writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
}
writer.Outdent();
writer.WriteLine("}");
// cache the data size for packed fields.
if (Descriptor.IsPacked) {
writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
}
writer.Outdent();
writer.WriteLine("}");
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
@ -11,6 +12,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateMembers(TextGenerator writer) {
if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
}
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@ -68,18 +72,60 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateParsingCode(TextGenerator writer) {
writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
if (Descriptor.IsPacked) {
writer.WriteLine("int length = input.ReadInt32();");
writer.WriteLine("int limit = input.PushLimit(length);");
writer.WriteLine("while (!input.ReachedLimit) {");
writer.WriteLine(" Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
writer.WriteLine("}");
writer.WriteLine("input.PopLimit(limit);");
} else {
writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
}
}
public void GenerateSerializationCode(TextGenerator writer) {
writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
writer.WriteLine("if ({0}_.Count > 0) {{", Name);
writer.Indent();
if (Descriptor.IsPacked) {
writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
writer.WriteLine(" output.Write{0}NoTag(element);", CapitalizedTypeName);
writer.WriteLine("}");
} else {
writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
writer.WriteLine("}");
}
writer.Outdent();
writer.WriteLine("}");
}
public void GenerateSerializedSizeCode(TextGenerator writer) {
writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, element);", CapitalizedTypeName, Number);
writer.WriteLine("{");
writer.Indent();
writer.WriteLine("int dataSize = 0;");
if (FixedSize == -1) {
writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
writer.WriteLine(" dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);", CapitalizedTypeName, Number);
writer.WriteLine("}");
} else {
writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
}
writer.WriteLine("size += dataSize;");
int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
if (Descriptor.IsPacked) {
writer.WriteLine("size += {0};", tagSize);
writer.WriteLine("size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);");
} else {
writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
}
// cache the data size for packed fields.
if (Descriptor.IsPacked) {
writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
}
writer.Outdent();
writer.WriteLine("}");
}
}

View File

@ -73,6 +73,20 @@ namespace Google.ProtocolBuffers {
TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
}
[Test]
public void PackedSerialization() {
IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet());
TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString()));
Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString());
}
[Test]
public void PackedParsing() {
AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder());
AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build();
TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage);
}
[Test]
public void OptimizedForSize() {
// We're mostly only Checking that this class was compiled successfully.

View File

@ -196,6 +196,18 @@ namespace Google.ProtocolBuffers {
}
}
/// <summary>
/// Tests writing a whole message with every packed field type. Ensures the
/// wire format of packed fields is compatible with C++.
/// </summary>
[Test]
public void WriteWholePackedFieldsMessage() {
TestPackedTypes message = TestUtil.GetPackedSet();
byte[] rawBytes = message.ToByteArray();
TestUtil.AssertEqualBytes(TestUtil.GetGoldenPackedFieldsMessage().ToByteArray(),
rawBytes);
}
[Test]
public void EncodeZigZag32() {

View File

@ -38,11 +38,13 @@ namespace Google.ProtocolBuffers {
private ReflectionTester reflectionTester;
private ReflectionTester extensionsReflectionTester;
private ReflectionTester packedReflectionTester;
[SetUp]
public void SetUp() {
reflectionTester = ReflectionTester.CreateTestAllTypesInstance();
extensionsReflectionTester = ReflectionTester.CreateTestAllExtensionsInstance();
packedReflectionTester = ReflectionTester.CreateTestPackedTypesInstance();
}
[Test]
@ -135,6 +137,33 @@ namespace Google.ProtocolBuffers {
reflectionTester.AssertAllFieldsSetViaReflection(message2);
}
[Test]
public void DynamicMessagePackedSerialization() {
IBuilder builder = DynamicMessage.CreateBuilder(TestPackedTypes.Descriptor);
packedReflectionTester.SetPackedFieldsViaReflection(builder);
IMessage message = builder.WeakBuild();
ByteString rawBytes = message.ToByteString();
TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes);
TestUtil.AssertPackedFieldsSet(message2);
// In fact, the serialized forms should be exactly the same, byte-for-byte.
Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), rawBytes);
}
[Test]
public void testDynamicMessagePackedParsing() {
TestPackedTypes.Builder builder = TestPackedTypes.CreateBuilder();
TestUtil.SetPackedFields(builder);
TestPackedTypes message = builder.Build();
ByteString rawBytes = message.ToByteString();
IMessage message2 = DynamicMessage.ParseFrom(TestPackedTypes.Descriptor, rawBytes);
packedReflectionTester.AssertPackedFieldsSetViaReflection(message2);
}
[Test]
public void DynamicMessageCopy() {
TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();

File diff suppressed because it is too large Load Diff

View File

@ -17,101 +17,97 @@ namespace Google.ProtocolBuffers.TestProtos {
"Ci1nb29nbGUvcHJvdG9idWYvdW5pdHRlc3RfY3VzdG9tX29wdGlvbnMucHJv" +
"dG8SEXByb3RvYnVmX3VuaXR0ZXN0GiRnb29nbGUvcHJvdG9idWYvY3NoYXJw" +
"X29wdGlvbnMucHJvdG8aIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlwdG9yLnBy" +
"b3RvIpoBChxUZXN0TWVzc2FnZVdpdGhDdXN0b21PcHRpb25zEioKBmZpZWxk" +
"MRgBIAEoCUIaCAHB4MMdLeF1CgIAAADB4MMdLeF1CgIAAAAiPAoGQW5FbnVt" +
"Eg8KC0FORU5VTV9WQUwxEAESDwoLQU5FTlVNX1ZBTDIQAhoQxfbJHev8///F" +
"9skd6/z//zoQCADg6cIdyP//////////ASIYChZDdXN0b21PcHRpb25Gb29S" +
"ZXF1ZXN0IhkKF0N1c3RvbU9wdGlvbkZvb1Jlc3BvbnNlIm0KGkR1bW15TWVz" +
"c2FnZUNvbnRhaW5pbmdFbnVtIk8KDFRlc3RFbnVtVHlwZRIaChZURVNUX09Q" +
"VElPTl9FTlVNX1RZUEUxEBYSIwoWVEVTVF9PUFRJT05fRU5VTV9UWVBFMhDp" +
"//////////8BIiEKH0R1bW15TWVzc2FnZUludmFsaWRBc09wdGlvblR5cGUi" +
"swEKHEN1c3RvbU9wdGlvbk1pbkludGVnZXJWYWx1ZXM6kgGZ1qgdAAAAAAAA" +
"AICZ1qgdAAAAAAAAAICtja8dAAAAgK2Nrx0AAACAke6vHQAAAAAAAAAAke6v" +
"HQAAAAAAAAAAnfWvHQAAAACd9a8dAAAAAPiXsB3///////////8BgMSwHf//" +
"//8P+PWwHQCAk7IdALC8sh2AgICAgICAgIAB6MayHYCAgID4/////wHQ3rId" +
"ACK6AQocQ3VzdG9tT3B0aW9uTWF4SW50ZWdlclZhbHVlczqZAZnWqB3/////" +
"////f5nWqB3/////////f62Nrx3///9/rY2vHf///3+R7q8d//////////+R" +
"7q8d//////////+d9a8d/////531rx3/////+JewHf7//////////wGAxLAd" +
"/v///w/49bAd////////////AYCTsh3/////D7C8sh3//////////3/oxrId" +
"/////wfQ3rIdASKCAQoXQ3VzdG9tT3B0aW9uT3RoZXJWYWx1ZXM6Z4jZoh3p" +
"//////////8BstmiHQtIZWxsbwBXb3JsZKrcoh0OSGVsbG8sICJXb3JsZCLp" +
"3KId+1mMQsrA8z/p3KId+1mMQsrA8z/136Md54dFQfXfox3nh0VB6MayHZz/" +
"/////////wEiSAocU2V0dGluZ1JlYWxzRnJvbVBvc2l0aXZlSW50czoo6dyi" +
"HQAAAAAAQGNA6dyiHQAAAAAAQGNA9d+jHQAAQEH136MdAABAQSJIChxTZXR0" +
"aW5nUmVhbHNGcm9tTmVnYXRpdmVJbnRzOijp3KIdAAAAAABAY8Dp3KIdAAAA" +
"AABAY8D136MdAABAwfXfox0AAEDBIisKEkNvbXBsZXhPcHRpb25UeXBlMRIL" +
"CgNmb28YASABKAUqCAhkEICAgIACIsECChJDb21wbGV4T3B0aW9uVHlwZTIS" +
"MgoDYmFyGAEgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdGlv" +
"blR5cGUxEgsKA2JhehgCIAEoBRJGCgRmcmVkGAMgASgLMjgucHJvdG9idWZf" +
"dW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUyLkNvbXBsZXhPcHRpb25UeXBl" +
"NBqXAQoSQ29tcGxleE9wdGlvblR5cGU0Eg0KBXdhbGRvGAEgASgFMnIKDGNv" +
"bXBsZXhfb3B0NBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiK" +
"9dEDIAEoCzI4LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBl" +
"Mi5Db21wbGV4T3B0aW9uVHlwZTQqCAhkEICAgIACIpwBChJDb21wbGV4T3B0" +
"aW9uVHlwZTMSCwoDcXV4GAEgASgFElQKEmNvbXBsZXhvcHRpb250eXBlNRgC" +
"IAEoCjI4LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMy5D" +
"b21wbGV4T3B0aW9uVHlwZTUaIwoSQ29tcGxleE9wdGlvblR5cGU1Eg0KBXBs" +
"dWdoGAMgASgFIh8KC0NvbXBsZXhPcHQ2EhAKBXh5enp5GN+/zwMgASgFItAB" +
"ChVWYXJpb3VzQ29tcGxleE9wdGlvbnM6tgHj3Pwc+P37HBjk3Pwc0qiPHQMI" +
"sw/63pAdAggJ+t6QHQQTGBYUqv2QHQMQ2weq/ZAdBvjmlx2OBar9kB0FCgMI" +
"5wWq/ZAdCAoG2IWeHc8Pqv2QHQoKCJL1nR0DCNgPqv2QHQjCrJcdAwjlBar9" +
"kB0LwqyXHQbYhZ4dzg+q/ZAdDcKslx0IkvWdHQMIyRCq/ZAdBRoDCMECouKV" +
"HQIIKqLilR0G2IWeHcQCouKVHQiS9Z0dAwjsBio2CgpNZXRob2RPcHQxEhMK" +
"D01FVEhPRE9QVDFfVkFMMRABEhMKD01FVEhPRE9QVDFfVkFMMhACMo4BChxU" +
"ZXN0U2VydmljZVdpdGhDdXN0b21PcHRpb25zEmMKA0ZvbxIpLnByb3RvYnVm" +
"X3VuaXR0ZXN0LkN1c3RvbU9wdGlvbkZvb1JlcXVlc3QaKi5wcm90b2J1Zl91" +
"bml0dGVzdC5DdXN0b21PcHRpb25Gb29SZXNwb25zZSIF4PqMHgIaCZCyix7T" +
"24DLSToyCglmaWxlX29wdDESHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlv" +
"bnMYjp3YAyABKAQ6OAoMbWVzc2FnZV9vcHQxEh8uZ29vZ2xlLnByb3RvYnVm" +
"Lk1lc3NhZ2VPcHRpb25zGJyt2AMgASgFOjQKCmZpZWxkX29wdDESHS5nb29n" +
"bGUucHJvdG9idWYuRmllbGRPcHRpb25zGIi82AMgASgGOjgKCmZpZWxkX29w" +
"dDISHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGLmh2QMgASgFOgI0" +
"MjoyCgllbnVtX29wdDESHC5nb29nbGUucHJvdG9idWYuRW51bU9wdGlvbnMY" +
"6J7ZAyABKA86OAoMc2VydmljZV9vcHQxEh8uZ29vZ2xlLnByb3RvYnVmLlNl" +
"cnZpY2VPcHRpb25zGKK24QMgASgSOlUKC21ldGhvZF9vcHQxEh4uZ29vZ2xl" +
"LnByb3RvYnVmLk1ldGhvZE9wdGlvbnMYrM/hAyABKA4yHS5wcm90b2J1Zl91" +
"bml0dGVzdC5NZXRob2RPcHQxOjQKCGJvb2xfb3B0Eh8uZ29vZ2xlLnByb3Rv" +
"YnVmLk1lc3NhZ2VPcHRpb25zGOqr1gMgASgIOjUKCWludDMyX29wdBIfLmdv" +
"b2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjtqNYDIAEoBTo1CglpbnQ2" +
"NF9vcHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYxqfWAyAB" +
"KAM6NgoKdWludDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0" +
"aW9ucxiwotYDIAEoDTo2Cgp1aW50NjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVm" +
"Lk1lc3NhZ2VPcHRpb25zGN+O1gMgASgEOjYKCnNpbnQzMl9vcHQSHy5nb29n" +
"bGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYwIjWAyABKBE6NgoKc2ludDY0" +
"X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxj/gtYDIAEo" +
"Ejo3CgtmaXhlZDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0" +
"aW9ucxjT/tUDIAEoBzo3CgtmaXhlZDY0X29wdBIfLmdvb2dsZS5wcm90b2J1" +
"Zi5NZXNzYWdlT3B0aW9ucxji/dUDIAEoBjo4CgxzZml4ZWQzMl9vcHQSHy5n" +
"b29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY1fHVAyABKA86OAoMc2Zp" +
"eGVkNjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGOOK" +
"1QMgASgQOjUKCWZsb2F0X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdl" +
"T3B0aW9ucxj+u9QDIAEoAjo2Cgpkb3VibGVfb3B0Eh8uZ29vZ2xlLnByb3Rv" +
"YnVmLk1lc3NhZ2VPcHRpb25zGM2r1AMgASgBOjYKCnN0cmluZ19vcHQSHy5n" +
"b29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYxavUAyABKAk6NQoJYnl0" +
"ZXNfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJar1AMg" +
"ASgMOnAKCGVudW1fb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRp" +
"b25zGJGr1AMgASgOMjoucHJvdG9idWZfdW5pdHRlc3QuRHVtbXlNZXNzYWdl" +
"Q29udGFpbmluZ0VudW0uVGVzdEVudW1UeXBlOnAKEG1lc3NhZ2VfdHlwZV9v" +
"cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYr/LTAyABKAsy" +
"Mi5wcm90b2J1Zl91bml0dGVzdC5EdW1teU1lc3NhZ2VJbnZhbGlkQXNPcHRp" +
"b25UeXBlOjYKBHF1dXgSJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0" +
"aW9uVHlwZTEY2+DTAyABKAU6XgoFY29yZ2USJS5wcm90b2J1Zl91bml0dGVz" +
"dC5Db21wbGV4T3B0aW9uVHlwZTEY0t7TAyABKAsyJS5wcm90b2J1Zl91bml0" +
"dGVzdC5Db21wbGV4T3B0aW9uVHlwZTM6OAoGZ3JhdWx0EiUucHJvdG9idWZf" +
"dW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUyGO/80gMgASgFOl8KBmdhcnBs" +
"eRIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMhjI9dID" +
"IAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMTpf" +
"Cgxjb21wbGV4X29wdDESHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlv" +
"bnMYpNzSAyABKAsyJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9u" +
"VHlwZTE6XwoMY29tcGxleF9vcHQyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3Nh" +
"Z2VPcHRpb25zGNWP0gMgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxl" +
"eE9wdGlvblR5cGUyOl8KDGNvbXBsZXhfb3B0MxIfLmdvb2dsZS5wcm90b2J1" +
"Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" +
"LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" +
"cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" +
"aXR0ZXN0LkNvbXBsZXhPcHQ2Qk/CPkMKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZl" +
"cnMuVGVzdFByb3RvcxIeVW5pdFRlc3RDdXN0b21PcHRpb25zUHJvdG9GaWxl" +
"8OjBHeqtwOUk"),
"b3RvIoYBChxUZXN0TWVzc2FnZVdpdGhDdXN0b21PcHRpb25zEh4KBmZpZWxk" +
"MRgBIAEoCUIOCAHB4MMdLeF1CgIAAAAiNAoGQW5FbnVtEg8KC0FORU5VTV9W" +
"QUwxEAESDwoLQU5FTlVNX1ZBTDIQAhoIxfbJHev8//86EAgA4OnCHcj/////" +
"/////wEiGAoWQ3VzdG9tT3B0aW9uRm9vUmVxdWVzdCIZChdDdXN0b21PcHRp" +
"b25Gb29SZXNwb25zZSJtChpEdW1teU1lc3NhZ2VDb250YWluaW5nRW51bSJP" +
"CgxUZXN0RW51bVR5cGUSGgoWVEVTVF9PUFRJT05fRU5VTV9UWVBFMRAWEiMK" +
"FlRFU1RfT1BUSU9OX0VOVU1fVFlQRTIQ6f//////////ASIhCh9EdW1teU1l" +
"c3NhZ2VJbnZhbGlkQXNPcHRpb25UeXBlIooBChxDdXN0b21PcHRpb25NaW5J" +
"bnRlZ2VyVmFsdWVzOmqZ1qgdAAAAAAAAAICtja8dAAAAgJHurx0AAAAAAAAA" +
"AJ31rx0AAAAA+JewHf///////////wGAxLAd/////w/49bAdAICTsh0AsLyy" +
"HYCAgICAgICAgAHoxrIdgICAgPj/////AdDesh0AIpEBChxDdXN0b21PcHRp" +
"b25NYXhJbnRlZ2VyVmFsdWVzOnGZ1qgd/////////3+tja8d////f5Hurx3/" +
"/////////531rx3/////+JewHf7//////////wGAxLAd/v///w/49bAd////" +
"////////AYCTsh3/////D7C8sh3//////////3/oxrId/////wfQ3rIdASJu" +
"ChdDdXN0b21PcHRpb25PdGhlclZhbHVlczpTiNmiHen//////////wGy2aId" +
"C0hlbGxvAFdvcmxkqtyiHQ5IZWxsbywgIldvcmxkIuncoh37WYxCysDzP/Xf" +
"ox3nh0VB6MayHZz//////////wEiNAocU2V0dGluZ1JlYWxzRnJvbVBvc2l0" +
"aXZlSW50czoU6dyiHQAAAAAAQGNA9d+jHQAAQEEiNAocU2V0dGluZ1JlYWxz" +
"RnJvbU5lZ2F0aXZlSW50czoU6dyiHQAAAAAAQGPA9d+jHQAAQMEiKwoSQ29t" +
"cGxleE9wdGlvblR5cGUxEgsKA2ZvbxgBIAEoBSoICGQQgICAgAIiwQIKEkNv" +
"bXBsZXhPcHRpb25UeXBlMhIyCgNiYXIYASABKAsyJS5wcm90b2J1Zl91bml0" +
"dGVzdC5Db21wbGV4T3B0aW9uVHlwZTESCwoDYmF6GAIgASgFEkYKBGZyZWQY" +
"AyABKAsyOC5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTIu" +
"Q29tcGxleE9wdGlvblR5cGU0GpcBChJDb21wbGV4T3B0aW9uVHlwZTQSDQoF" +
"d2FsZG8YASABKAUycgoMY29tcGxleF9vcHQ0Eh8uZ29vZ2xlLnByb3RvYnVm" +
"Lk1lc3NhZ2VPcHRpb25zGIr10QMgASgLMjgucHJvdG9idWZfdW5pdHRlc3Qu" +
"Q29tcGxleE9wdGlvblR5cGUyLkNvbXBsZXhPcHRpb25UeXBlNCoICGQQgICA" +
"gAIinAEKEkNvbXBsZXhPcHRpb25UeXBlMxILCgNxdXgYASABKAUSVAoSY29t" +
"cGxleG9wdGlvbnR5cGU1GAIgASgKMjgucHJvdG9idWZfdW5pdHRlc3QuQ29t" +
"cGxleE9wdGlvblR5cGUzLkNvbXBsZXhPcHRpb25UeXBlNRojChJDb21wbGV4" +
"T3B0aW9uVHlwZTUSDQoFcGx1Z2gYAyABKAUiHwoLQ29tcGxleE9wdDYSEAoF" +
"eHl6enkY37/PAyABKAUi0AEKFVZhcmlvdXNDb21wbGV4T3B0aW9uczq2AePc" +
"/Bz4/fscGOTc/BzSqI8dAwizD/rekB0CCAn63pAdBBMYFhSq/ZAdAxDbB6r9" +
"kB0G+OaXHY4Fqv2QHQUKAwjnBar9kB0ICgbYhZ4dzw+q/ZAdCgoIkvWdHQMI" +
"2A+q/ZAdCMKslx0DCOUFqv2QHQvCrJcdBtiFnh3OD6r9kB0NwqyXHQiS9Z0d" +
"AwjJEKr9kB0FGgMIwQKi4pUdAggqouKVHQbYhZ4dxAKi4pUdCJL1nR0DCOwG" +
"KjYKCk1ldGhvZE9wdDESEwoPTUVUSE9ET1BUMV9WQUwxEAESEwoPTUVUSE9E" +
"T1BUMV9WQUwyEAIyjgEKHFRlc3RTZXJ2aWNlV2l0aEN1c3RvbU9wdGlvbnMS" +
"YwoDRm9vEikucHJvdG9idWZfdW5pdHRlc3QuQ3VzdG9tT3B0aW9uRm9vUmVx" +
"dWVzdBoqLnByb3RvYnVmX3VuaXR0ZXN0LkN1c3RvbU9wdGlvbkZvb1Jlc3Bv" +
"bnNlIgXg+oweAhoJkLKLHtPbgMtJOjIKCWZpbGVfb3B0MRIcLmdvb2dsZS5w" +
"cm90b2J1Zi5GaWxlT3B0aW9ucxiOndgDIAEoBDo4CgxtZXNzYWdlX29wdDES" +
"Hy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnK3YAyABKAU6NAoK" +
"ZmllbGRfb3B0MRIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMYiLzY" +
"AyABKAY6OAoKZmllbGRfb3B0MhIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9w" +
"dGlvbnMYuaHZAyABKAU6AjQyOjIKCWVudW1fb3B0MRIcLmdvb2dsZS5wcm90" +
"b2J1Zi5FbnVtT3B0aW9ucxjontkDIAEoDzo4CgxzZXJ2aWNlX29wdDESHy5n" +
"b29nbGUucHJvdG9idWYuU2VydmljZU9wdGlvbnMYorbhAyABKBI6VQoLbWV0" +
"aG9kX29wdDESHi5nb29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxisz+ED" +
"IAEoDjIdLnByb3RvYnVmX3VuaXR0ZXN0Lk1ldGhvZE9wdDE6NAoIYm9vbF9v" +
"cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY6qvWAyABKAg6" +
"NQoJaW50MzJfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25z" +
"GO2o1gMgASgFOjUKCWludDY0X29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNz" +
"YWdlT3B0aW9ucxjGp9YDIAEoAzo2Cgp1aW50MzJfb3B0Eh8uZ29vZ2xlLnBy" +
"b3RvYnVmLk1lc3NhZ2VPcHRpb25zGLCi1gMgASgNOjYKCnVpbnQ2NF9vcHQS" +
"Hy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY347WAyABKAQ6NgoK" +
"c2ludDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjA" +
"iNYDIAEoETo2CgpzaW50NjRfb3B0Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3Nh" +
"Z2VPcHRpb25zGP+C1gMgASgSOjcKC2ZpeGVkMzJfb3B0Eh8uZ29vZ2xlLnBy" +
"b3RvYnVmLk1lc3NhZ2VPcHRpb25zGNP+1QMgASgHOjcKC2ZpeGVkNjRfb3B0" +
"Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGOL91QMgASgGOjgK" +
"DHNmaXhlZDMyX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9u" +
"cxjV8dUDIAEoDzo4CgxzZml4ZWQ2NF9vcHQSHy5nb29nbGUucHJvdG9idWYu" +
"TWVzc2FnZU9wdGlvbnMY44rVAyABKBA6NQoJZmxvYXRfb3B0Eh8uZ29vZ2xl" +
"LnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGP671AMgASgCOjYKCmRvdWJsZV9v" +
"cHQSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYzavUAyABKAE6" +
"NgoKc3RyaW5nX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9u" +
"cxjFq9QDIAEoCTo1CglieXRlc19vcHQSHy5nb29nbGUucHJvdG9idWYuTWVz" +
"c2FnZU9wdGlvbnMYlqvUAyABKAw6cAoIZW51bV9vcHQSHy5nb29nbGUucHJv" +
"dG9idWYuTWVzc2FnZU9wdGlvbnMYkavUAyABKA4yOi5wcm90b2J1Zl91bml0" +
"dGVzdC5EdW1teU1lc3NhZ2VDb250YWluaW5nRW51bS5UZXN0RW51bVR5cGU6" +
"cAoQbWVzc2FnZV90eXBlX29wdBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdl" +
"T3B0aW9ucxiv8tMDIAEoCzIyLnByb3RvYnVmX3VuaXR0ZXN0LkR1bW15TWVz" +
"c2FnZUludmFsaWRBc09wdGlvblR5cGU6NgoEcXV1eBIlLnByb3RvYnVmX3Vu" +
"aXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMRjb4NMDIAEoBTpeCgVjb3JnZRIl" +
"LnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMRjS3tMDIAEo" +
"CzIlLnByb3RvYnVmX3VuaXR0ZXN0LkNvbXBsZXhPcHRpb25UeXBlMzo4CgZn" +
"cmF1bHQSJS5wcm90b2J1Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTIY" +
"7/zSAyABKAU6XwoGZ2FycGx5EiUucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxl" +
"eE9wdGlvblR5cGUyGMj10gMgASgLMiUucHJvdG9idWZfdW5pdHRlc3QuQ29t" +
"cGxleE9wdGlvblR5cGUxOl8KDGNvbXBsZXhfb3B0MRIfLmdvb2dsZS5wcm90" +
"b2J1Zi5NZXNzYWdlT3B0aW9ucxik3NIDIAEoCzIlLnByb3RvYnVmX3VuaXR0" +
"ZXN0LkNvbXBsZXhPcHRpb25UeXBlMTpfCgxjb21wbGV4X29wdDISHy5nb29n" +
"bGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMY1Y/SAyABKAsyJS5wcm90b2J1" +
"Zl91bml0dGVzdC5Db21wbGV4T3B0aW9uVHlwZTI6XwoMY29tcGxleF9vcHQz" +
"Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGO+L0gMgASgLMiUu" +
"cHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdGlvblR5cGUzOlcKC2NvbXBs" +
"ZXhvcHQ2Eh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGMzLzwMg" +
"ASgKMh4ucHJvdG9idWZfdW5pdHRlc3QuQ29tcGxleE9wdDZCT8I+QwohR29v" +
"Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEh5Vbml0VGVzdEN1c3Rv" +
"bU9wdGlvbnNQcm90b0ZpbGXw6MEd6q3A5SQ="),
new pbd::FileDescriptor[] {
global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor,
global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,

File diff suppressed because it is too large Load Diff

View File

@ -158,6 +158,21 @@ namespace Google.ProtocolBuffers {
registry.Add(UnitTestProtoFile.DefaultImportEnumExtension);
registry.Add(UnitTestProtoFile.DefaultStringPieceExtension);
registry.Add(UnitTestProtoFile.DefaultCordExtension);
registry.Add(UnitTestProtoFile.PackedInt32Extension);
registry.Add(UnitTestProtoFile.PackedInt64Extension);
registry.Add(UnitTestProtoFile.PackedUint32Extension);
registry.Add(UnitTestProtoFile.PackedUint64Extension);
registry.Add(UnitTestProtoFile.PackedSint32Extension);
registry.Add(UnitTestProtoFile.PackedSint64Extension);
registry.Add(UnitTestProtoFile.PackedFixed32Extension);
registry.Add(UnitTestProtoFile.PackedFixed64Extension);
registry.Add(UnitTestProtoFile.PackedSfixed32Extension);
registry.Add(UnitTestProtoFile.PackedSfixed64Extension);
registry.Add(UnitTestProtoFile.PackedFloatExtension);
registry.Add(UnitTestProtoFile.PackedDoubleExtension);
registry.Add(UnitTestProtoFile.PackedBoolExtension);
registry.Add(UnitTestProtoFile.PackedEnumExtension);
}
internal static string ReadTextFromFile(string filePath) {
@ -653,6 +668,18 @@ namespace Google.ProtocolBuffers {
return builder.Build();
}
public static TestPackedTypes GetPackedSet() {
TestPackedTypes.Builder builder = TestPackedTypes.CreateBuilder();
SetPackedFields(builder);
return builder.Build();
}
public static TestPackedExtensions GetPackedExtensionsSet() {
TestPackedExtensions.Builder builder = TestPackedExtensions.CreateBuilder();
SetPackedExtensions(builder);
return builder.Build();
}
/// <summary>
/// Sets every field of the specified builder to the values expected by
/// AssertAllExtensionsSet.
@ -1373,6 +1400,184 @@ namespace Google.ProtocolBuffers {
Assert.AreEqual("123", message.GetExtension(UnitTestProtoFile.DefaultCordExtension));
}
/// <summary>
/// Set every field of the specified message to a unique value.
/// </summary>
public static void SetPackedFields(TestPackedTypes.Builder message) {
message.AddPackedInt32(601);
message.AddPackedInt64(602);
message.AddPackedUint32(603);
message.AddPackedUint64(604);
message.AddPackedSint32(605);
message.AddPackedSint64(606);
message.AddPackedFixed32(607);
message.AddPackedFixed64(608);
message.AddPackedSfixed32(609);
message.AddPackedSfixed64(610);
message.AddPackedFloat(611);
message.AddPackedDouble(612);
message.AddPackedBool(true);
message.AddPackedEnum(ForeignEnum.FOREIGN_BAR);
// Add a second one of each field.
message.AddPackedInt32(701);
message.AddPackedInt64(702);
message.AddPackedUint32(703);
message.AddPackedUint64(704);
message.AddPackedSint32(705);
message.AddPackedSint64(706);
message.AddPackedFixed32(707);
message.AddPackedFixed64(708);
message.AddPackedSfixed32(709);
message.AddPackedSfixed64(710);
message.AddPackedFloat(711);
message.AddPackedDouble(712);
message.AddPackedBool(false);
message.AddPackedEnum(ForeignEnum.FOREIGN_BAZ);
}
/// <summary>
/// Asserts that all the fields of the specified message are set to the values assigned
/// in SetPackedFields.
/// </summary>
public static void AssertPackedFieldsSet(TestPackedTypes message) {
Assert.AreEqual(2, message.PackedInt32Count);
Assert.AreEqual(2, message.PackedInt64Count);
Assert.AreEqual(2, message.PackedUint32Count);
Assert.AreEqual(2, message.PackedUint64Count);
Assert.AreEqual(2, message.PackedSint32Count);
Assert.AreEqual(2, message.PackedSint64Count);
Assert.AreEqual(2, message.PackedFixed32Count);
Assert.AreEqual(2, message.PackedFixed64Count);
Assert.AreEqual(2, message.PackedSfixed32Count);
Assert.AreEqual(2, message.PackedSfixed64Count);
Assert.AreEqual(2, message.PackedFloatCount);
Assert.AreEqual(2, message.PackedDoubleCount);
Assert.AreEqual(2, message.PackedBoolCount);
Assert.AreEqual(2, message.PackedEnumCount);
Assert.AreEqual(601, message.GetPackedInt32(0));
Assert.AreEqual(602, message.GetPackedInt64(0));
Assert.AreEqual(603, message.GetPackedUint32(0));
Assert.AreEqual(604, message.GetPackedUint64(0));
Assert.AreEqual(605, message.GetPackedSint32(0));
Assert.AreEqual(606, message.GetPackedSint64(0));
Assert.AreEqual(607, message.GetPackedFixed32(0));
Assert.AreEqual(608, message.GetPackedFixed64(0));
Assert.AreEqual(609, message.GetPackedSfixed32(0));
Assert.AreEqual(610, message.GetPackedSfixed64(0));
Assert.AreEqual(611, message.GetPackedFloat(0), 0.0);
Assert.AreEqual(612, message.GetPackedDouble(0), 0.0);
Assert.AreEqual(true, message.GetPackedBool(0));
Assert.AreEqual(ForeignEnum.FOREIGN_BAR, message.GetPackedEnum(0));
Assert.AreEqual(701, message.GetPackedInt32(1));
Assert.AreEqual(702, message.GetPackedInt64(1));
Assert.AreEqual(703, message.GetPackedUint32(1));
Assert.AreEqual(704, message.GetPackedUint64(1));
Assert.AreEqual(705, message.GetPackedSint32(1));
Assert.AreEqual(706, message.GetPackedSint64(1));
Assert.AreEqual(707, message.GetPackedFixed32(1));
Assert.AreEqual(708, message.GetPackedFixed64(1));
Assert.AreEqual(709, message.GetPackedSfixed32(1));
Assert.AreEqual(710, message.GetPackedSfixed64(1));
Assert.AreEqual(711, message.GetPackedFloat(1), 0.0);
Assert.AreEqual(712, message.GetPackedDouble(1), 0.0);
Assert.AreEqual(false, message.GetPackedBool(1));
Assert.AreEqual(ForeignEnum.FOREIGN_BAZ, message.GetPackedEnum(1));
}
public static void SetPackedExtensions(TestPackedExtensions.Builder message) {
message.AddExtension(UnitTestProtoFile.PackedInt32Extension, 601);
message.AddExtension(UnitTestProtoFile.PackedInt64Extension, 602L);
message.AddExtension(UnitTestProtoFile.PackedUint32Extension, 603U);
message.AddExtension(UnitTestProtoFile.PackedUint64Extension, 604UL);
message.AddExtension(UnitTestProtoFile.PackedSint32Extension, 605);
message.AddExtension(UnitTestProtoFile.PackedSint64Extension, 606L);
message.AddExtension(UnitTestProtoFile.PackedFixed32Extension, 607U);
message.AddExtension(UnitTestProtoFile.PackedFixed64Extension, 608UL);
message.AddExtension(UnitTestProtoFile.PackedSfixed32Extension, 609);
message.AddExtension(UnitTestProtoFile.PackedSfixed64Extension, 610L);
message.AddExtension(UnitTestProtoFile.PackedFloatExtension, 611F);
message.AddExtension(UnitTestProtoFile.PackedDoubleExtension, 612D);
message.AddExtension(UnitTestProtoFile.PackedBoolExtension, true);
message.AddExtension(UnitTestProtoFile.PackedEnumExtension, ForeignEnum.FOREIGN_BAR);
// Add a second one of each field.
message.AddExtension(UnitTestProtoFile.PackedInt32Extension, 701);
message.AddExtension(UnitTestProtoFile.PackedInt64Extension, 702L);
message.AddExtension(UnitTestProtoFile.PackedUint32Extension, 703U);
message.AddExtension(UnitTestProtoFile.PackedUint64Extension, 704UL);
message.AddExtension(UnitTestProtoFile.PackedSint32Extension, 705);
message.AddExtension(UnitTestProtoFile.PackedSint64Extension, 706L);
message.AddExtension(UnitTestProtoFile.PackedFixed32Extension, 707U);
message.AddExtension(UnitTestProtoFile.PackedFixed64Extension, 708UL);
message.AddExtension(UnitTestProtoFile.PackedSfixed32Extension, 709);
message.AddExtension(UnitTestProtoFile.PackedSfixed64Extension, 710L);
message.AddExtension(UnitTestProtoFile.PackedFloatExtension, 711F);
message.AddExtension(UnitTestProtoFile.PackedDoubleExtension, 712D);
message.AddExtension(UnitTestProtoFile.PackedBoolExtension, false);
message.AddExtension(UnitTestProtoFile.PackedEnumExtension, ForeignEnum.FOREIGN_BAZ);
}
public static void AssertPackedExtensionsSet(TestPackedExtensions message) {
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedInt32Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedInt64Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedUint32Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedUint64Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSint32Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSint64Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFixed32Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFixed64Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSfixed32Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedSfixed64Extension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedFloatExtension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedDoubleExtension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedBoolExtension));
Assert.AreEqual(2, message.GetExtensionCount(UnitTestProtoFile.PackedEnumExtension));
Assert.AreEqual(601, message.GetExtension(UnitTestProtoFile.PackedInt32Extension, 0));
Assert.AreEqual(602L, message.GetExtension(UnitTestProtoFile.PackedInt64Extension, 0));
Assert.AreEqual(603, message.GetExtension(UnitTestProtoFile.PackedUint32Extension, 0));
Assert.AreEqual(604L, message.GetExtension(UnitTestProtoFile.PackedUint64Extension, 0));
Assert.AreEqual(605, message.GetExtension(UnitTestProtoFile.PackedSint32Extension, 0));
Assert.AreEqual(606L, message.GetExtension(UnitTestProtoFile.PackedSint64Extension, 0));
Assert.AreEqual(607, message.GetExtension(UnitTestProtoFile.PackedFixed32Extension, 0));
Assert.AreEqual(608L, message.GetExtension(UnitTestProtoFile.PackedFixed64Extension, 0));
Assert.AreEqual(609, message.GetExtension(UnitTestProtoFile.PackedSfixed32Extension, 0));
Assert.AreEqual(610L, message.GetExtension(UnitTestProtoFile.PackedSfixed64Extension, 0));
Assert.AreEqual(611F, message.GetExtension(UnitTestProtoFile.PackedFloatExtension, 0));
Assert.AreEqual(612D, message.GetExtension(UnitTestProtoFile.PackedDoubleExtension, 0));
Assert.AreEqual(true, message.GetExtension(UnitTestProtoFile.PackedBoolExtension, 0));
Assert.AreEqual(ForeignEnum.FOREIGN_BAR,
message.GetExtension(UnitTestProtoFile.PackedEnumExtension, 0));
Assert.AreEqual(701, message.GetExtension(UnitTestProtoFile.PackedInt32Extension, 1));
Assert.AreEqual(702L, message.GetExtension(UnitTestProtoFile.PackedInt64Extension, 1));
Assert.AreEqual(703, message.GetExtension(UnitTestProtoFile.PackedUint32Extension, 1));
Assert.AreEqual(704L, message.GetExtension(UnitTestProtoFile.PackedUint64Extension, 1));
Assert.AreEqual(705, message.GetExtension(UnitTestProtoFile.PackedSint32Extension, 1));
Assert.AreEqual(706L, message.GetExtension(UnitTestProtoFile.PackedSint64Extension, 1));
Assert.AreEqual(707, message.GetExtension(UnitTestProtoFile.PackedFixed32Extension, 1));
Assert.AreEqual(708L, message.GetExtension(UnitTestProtoFile.PackedFixed64Extension, 1));
Assert.AreEqual(709, message.GetExtension(UnitTestProtoFile.PackedSfixed32Extension, 1));
Assert.AreEqual(710L, message.GetExtension(UnitTestProtoFile.PackedSfixed64Extension, 1));
Assert.AreEqual(711F, message.GetExtension(UnitTestProtoFile.PackedFloatExtension, 1));
Assert.AreEqual(712D, message.GetExtension(UnitTestProtoFile.PackedDoubleExtension, 1));
Assert.AreEqual(false, message.GetExtension(UnitTestProtoFile.PackedBoolExtension, 1));
Assert.AreEqual(ForeignEnum.FOREIGN_BAZ, message.GetExtension(UnitTestProtoFile.PackedEnumExtension, 1));
}
private static ByteString goldenPackedFieldsMessage = null;
/// <summary>
/// Get the bytes of the "golden packed fields message". This is a serialized
/// TestPackedTypes with all fields set as they would be by SetPackedFields,
/// but it is loaded from a file on disk rather than generated dynamically.
/// The file is actually generated by C++ code, so testing against it verifies compatibility
/// with C++.
/// </summary>
public static ByteString GetGoldenPackedFieldsMessage() {
if (goldenPackedFieldsMessage == null) {
goldenPackedFieldsMessage = ReadBytesFromFile("golden_packed_fields_message");
}
return goldenPackedFieldsMessage;
}
/// <summary>
/// Helper to construct a byte array from a bunch of bytes.
/// </summary>

View File

@ -62,12 +62,20 @@ namespace Google.ProtocolBuffers {
TestUtil.AssertAllFieldsSet(message2);
}
[Test]
public void SerializationPacked() {
TestPackedTypes message = TestUtil.GetPackedSet();
ByteString rawBytes = message.ToByteString();
Assert.AreEqual(rawBytes.Length, message.SerializedSize);
TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes);
TestUtil.AssertPackedFieldsSet(message2);
}
[Test]
public void SerializeExtensions() {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serealize a TestAllExtensions then parse it as TestAllTypes
// so if we serialize a TestAllExtensions then parse it as TestAllTypes
// it should work.
TestAllExtensions message = TestUtil.GetAllExtensionsSet();
ByteString rawBytes = message.ToByteString();
Assert.AreEqual(rawBytes.Length, message.SerializedSize);
@ -77,6 +85,19 @@ namespace Google.ProtocolBuffers {
TestUtil.AssertAllFieldsSet(message2);
}
[Test]
public void SerializePackedExtensions() {
// TestPackedTypes and TestPackedExtensions should have compatible wire
// formats; check that they serialize to the same string.
TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
ByteString rawBytes = message.ToByteString();
TestPackedTypes message2 = TestUtil.GetPackedSet();
ByteString rawBytes2 = message2.ToByteString();
Assert.AreEqual(rawBytes, rawBytes2);
}
[Test]
public void ParseExtensions() {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
@ -90,12 +111,23 @@ namespace Google.ProtocolBuffers {
TestUtil.RegisterAllExtensions(registry);
registry = registry.AsReadOnly();
TestAllExtensions message2 =
TestAllExtensions.ParseFrom(rawBytes, registry);
TestAllExtensions message2 = TestAllExtensions.ParseFrom(rawBytes, registry);
TestUtil.AssertAllExtensionsSet(message2);
}
[Test]
public void ParsePackedExtensions() {
// Ensure that packed extensions can be properly parsed.
TestPackedExtensions message = TestUtil.GetPackedExtensionsSet();
ByteString rawBytes = message.ToByteString();
ExtensionRegistry registry = TestUtil.CreateExtensionRegistry();
TestPackedExtensions message2 = TestPackedExtensions.ParseFrom(rawBytes, registry);
TestUtil.AssertPackedExtensionsSet(message2);
}
[Test]
public void ExtensionsSerializedSize() {
Assert.AreEqual(TestUtil.GetAllSet().SerializedSize, TestUtil.GetAllExtensionsSet().SerializedSize);

View File

@ -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);

View File

@ -608,6 +608,20 @@ namespace Google.ProtocolBuffers {
RecomputeBufferSizeAfterLimit();
}
/// <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

View File

@ -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);
@ -687,6 +989,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>

View File

@ -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; }
}

View File

@ -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>

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

BIN
testdata/golden_packed_fields_message vendored Normal file

Binary file not shown.

View File

@ -1,10 +1,14 @@
Current task list (not in order)
- Performance framework
- Optionally remove dependencies to core and csharp options (2.0.3
will remove core dependency)
- Optionally remove dependencies to csharp options
- Remove multifile support
- Mono support
- Docs
- Clean up protogen code
- Add flags to protogen
- Avoid using reflection for messages which don't need it (is this
possible?)
- Add RegisterAllExtensions
- Add ToBuilder changes from Google's r92
- Silverlight changes (as per email to Jon)