Tidying up and extra tests.
This is mostly just making things internal instead of public, removing and reordering a bunch of code in CodedInputStream/CodedOutputStream, and generally tidying up.
This commit is contained in:
parent
b9d1d3891f
commit
f34d37a3d4
@ -0,0 +1,54 @@
|
||||
#region Copyright notice and license
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Google.Protobuf
|
||||
{
|
||||
internal static class CodedInputStreamExtensions
|
||||
{
|
||||
public static void AssertNextTag(this CodedInputStream input, uint expectedTag)
|
||||
{
|
||||
uint tag;
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
Assert.AreEqual(expectedTag, tag);
|
||||
}
|
||||
|
||||
public static T ReadMessage<T>(this CodedInputStream stream, MessageParser<T> parser)
|
||||
where T : IMessage<T>
|
||||
{
|
||||
var message = parser.CreateTemplate();
|
||||
stream.ReadMessage(message);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
@ -35,10 +35,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Google.Protobuf.Collections;
|
||||
using Google.Protobuf.Descriptors;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -62,7 +60,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64() and
|
||||
/// Parses the given bytes using ReadRawVarint32() and ReadRawVarint64()
|
||||
/// </summary>
|
||||
private static void AssertReadVarint(byte[] data, ulong value)
|
||||
{
|
||||
@ -232,66 +230,26 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual(0x7FFFFFFFFFFFFFFFL, CodedInputStream.DecodeZigZag64(0xFFFFFFFFFFFFFFFEL));
|
||||
Assert.AreEqual(unchecked((long) 0x8000000000000000L), CodedInputStream.DecodeZigZag64(0xFFFFFFFFFFFFFFFFL));
|
||||
}
|
||||
/*
|
||||
|
||||
[Test]
|
||||
public void ReadWholeMessage()
|
||||
public void ReadWholeMessage_VaryingBlockSizes()
|
||||
{
|
||||
TestAllTypes message = TestUtil.GetAllSet();
|
||||
TestAllTypes message = GeneratedMessageTest.GetSampleMessage();
|
||||
|
||||
byte[] rawBytes = message.ToByteArray();
|
||||
Assert.AreEqual(rawBytes.Length, message.SerializedSize);
|
||||
TestAllTypes message2 = TestAllTypes.ParseFrom(rawBytes);
|
||||
TestUtil.AssertAllFieldsSet(message2);
|
||||
Assert.AreEqual(rawBytes.Length, message.CalculateSize());
|
||||
TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(rawBytes);
|
||||
Assert.AreEqual(message, message2);
|
||||
|
||||
// Try different block sizes.
|
||||
for (int blockSize = 1; blockSize < 256; blockSize *= 2)
|
||||
{
|
||||
message2 = TestAllTypes.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize));
|
||||
TestUtil.AssertAllFieldsSet(message2);
|
||||
message2 = TestAllTypes.Parser.ParseFrom(new SmallBlockInputStream(rawBytes, blockSize));
|
||||
Assert.AreEqual(message, message2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void SkipWholeMessage()
|
||||
{
|
||||
TestAllTypes message = TestUtil.GetAllSet();
|
||||
byte[] rawBytes = message.ToByteArray();
|
||||
|
||||
// Create two parallel inputs. Parse one as unknown fields while using
|
||||
// skipField() to skip each field on the other. Expect the same tags.
|
||||
CodedInputStream input1 = CodedInputStream.CreateInstance(rawBytes);
|
||||
CodedInputStream input2 = CodedInputStream.CreateInstance(rawBytes);
|
||||
UnknownFieldSet.Builder unknownFields = UnknownFieldSet.CreateBuilder();
|
||||
|
||||
uint tag;
|
||||
string name;
|
||||
while (input1.ReadTag(out tag, out name))
|
||||
{
|
||||
uint tag2;
|
||||
Assert.IsTrue(input2.ReadTag(out tag2, out name));
|
||||
Assert.AreEqual(tag, tag2);
|
||||
|
||||
unknownFields.MergeFieldFrom(tag, input1);
|
||||
input2.SkipField();
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Test that a bug in SkipRawBytes has been fixed: if the skip
|
||||
/// skips exactly up to a limit, this should bnot break things
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void SkipRawBytesBug()
|
||||
{
|
||||
byte[] rawBytes = new byte[] {1, 2};
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(rawBytes);
|
||||
|
||||
int limit = input.PushLimit(1);
|
||||
input.SkipRawBytes(1);
|
||||
input.PopLimit(limit);
|
||||
Assert.AreEqual(2, input.ReadRawByte());
|
||||
}
|
||||
/*
|
||||
public void ReadHugeBlob()
|
||||
{
|
||||
// Allocate and initialize a 1MB blob.
|
||||
@ -302,24 +260,15 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
// Make a message containing it.
|
||||
TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
|
||||
TestUtil.SetAllFields(builder);
|
||||
builder.SetOptionalBytes(ByteString.CopyFrom(blob));
|
||||
TestAllTypes message = builder.Build();
|
||||
var message = new TestAllTypes { SingleBytes = ByteString.CopyFrom(blob) };
|
||||
|
||||
// Serialize and parse it. Make sure to parse from an InputStream, not
|
||||
// directly from a ByteString, so that CodedInputStream uses buffered
|
||||
// reading.
|
||||
TestAllTypes message2 = TestAllTypes.ParseFrom(message.ToByteString().CreateCodedInput());
|
||||
TestAllTypes message2 = TestAllTypes.Parser.ParseFrom(message.ToByteString());
|
||||
|
||||
Assert.AreEqual(message.OptionalBytes, message2.OptionalBytes);
|
||||
|
||||
// Make sure all the other fields were parsed correctly.
|
||||
TestAllTypes message3 = TestAllTypes.CreateBuilder(message2)
|
||||
.SetOptionalBytes(TestUtil.GetAllSet().OptionalBytes)
|
||||
.Build();
|
||||
TestUtil.AssertAllFieldsSet(message3);
|
||||
}*/
|
||||
Assert.AreEqual(message, message2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadMaliciouslyLargeBlob()
|
||||
@ -461,85 +410,15 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
enum TestNegEnum { None = 0, Value = -2 }
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnum()
|
||||
{
|
||||
byte[] bytes = new byte[10] { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 };
|
||||
byte[] bytes = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 };
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
Assert.AreEqual((int)TestNegEnum.Value, input.ReadEnum());
|
||||
Assert.AreEqual((int)SampleEnum.NegativeValue, input.ReadEnum());
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumPackedArray()
|
||||
{
|
||||
int arraySize = 1 + (10 * 5);
|
||||
int msgSize = 1 + 1 + arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
// Length-delimited to show we want the packed representation
|
||||
uint tag = WireFormat.MakeTag(8, WireFormat.WireType.LengthDelimited);
|
||||
output.WriteTag(tag);
|
||||
int size = 0;
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
size += CodedOutputStream.ComputeEnumSize(i);
|
||||
}
|
||||
output.WriteRawVarint32((uint) size);
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
output.WriteEnum(i);
|
||||
}
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>();
|
||||
values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int) x, x => (TestNegEnum) x));
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
Assert.AreEqual(TestNegEnum.None, values[0]);
|
||||
Assert.AreEqual(((TestNegEnum) (-1)), values[1]);
|
||||
Assert.AreEqual(TestNegEnum.Value, values[2]);
|
||||
Assert.AreEqual(((TestNegEnum)(-3)), values[3]);
|
||||
Assert.AreEqual(((TestNegEnum)(-4)), values[4]);
|
||||
Assert.AreEqual(((TestNegEnum)(-5)), values[5]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumArray()
|
||||
{
|
||||
int arraySize = 1 + 1 + (11 * 5);
|
||||
int msgSize = arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
uint tag = WireFormat.MakeTag(8, WireFormat.WireType.Varint);
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
output.WriteTag(tag);
|
||||
output.WriteEnum(i);
|
||||
}
|
||||
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
RepeatedField<TestNegEnum> values = new RepeatedField<TestNegEnum>();
|
||||
values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (TestNegEnum)x));
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
Assert.AreEqual(TestNegEnum.None, values[0]);
|
||||
Assert.AreEqual(((TestNegEnum)(-1)), values[1]);
|
||||
Assert.AreEqual(TestNegEnum.Value, values[2]);
|
||||
Assert.AreEqual(((TestNegEnum)(-3)), values[3]);
|
||||
Assert.AreEqual(((TestNegEnum)(-4)), values[4]);
|
||||
Assert.AreEqual(((TestNegEnum)(-5)), values[5]);
|
||||
}
|
||||
|
||||
//Issue 71: CodedInputStream.ReadBytes go to slow path unnecessarily
|
||||
[Test]
|
||||
public void TestSlowPathAvoidance()
|
||||
|
@ -35,9 +35,8 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Google.Protobuf.Collections;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Google.Protobuf
|
||||
@ -195,42 +194,24 @@ namespace Google.Protobuf
|
||||
0x9abcdef012345678UL);
|
||||
}
|
||||
|
||||
/*
|
||||
[Test]
|
||||
public void WriteWholeMessage()
|
||||
public void WriteWholeMessage_VaryingBlockSizes()
|
||||
{
|
||||
TestAllTypes message = TestUtil.GetAllSet();
|
||||
TestAllTypes message = GeneratedMessageTest.GetSampleMessage();
|
||||
|
||||
byte[] rawBytes = message.ToByteArray();
|
||||
TestUtil.AssertEqualBytes(TestUtil.GoldenMessage.ToByteArray(), rawBytes);
|
||||
|
||||
// Try different block sizes.
|
||||
for (int blockSize = 1; blockSize < 256; blockSize *= 2)
|
||||
{
|
||||
MemoryStream rawOutput = new MemoryStream();
|
||||
CodedOutputStream output =
|
||||
CodedOutputStream.CreateInstance(rawOutput, blockSize);
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(rawOutput, blockSize);
|
||||
message.WriteTo(output);
|
||||
output.Flush();
|
||||
TestUtil.AssertEqualBytes(rawBytes, rawOutput.ToArray());
|
||||
Assert.AreEqual(rawBytes, rawOutput.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
@ -296,68 +277,16 @@ namespace Google.Protobuf
|
||||
public void TestNegativeEnumNoTag()
|
||||
{
|
||||
Assert.AreEqual(10, CodedOutputStream.ComputeInt32Size(-2));
|
||||
Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) TestNegEnum.Value));
|
||||
Assert.AreEqual(10, CodedOutputStream.ComputeEnumSize((int) SampleEnum.NegativeValue));
|
||||
|
||||
byte[] bytes = new byte[10];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
output.WriteEnum((int) TestNegEnum.Value);
|
||||
output.WriteEnum((int) SampleEnum.NegativeValue);
|
||||
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
Assert.AreEqual("FE-FF-FF-FF-FF-FF-FF-FF-FF-01", BitConverter.ToString(bytes));
|
||||
}
|
||||
|
||||
enum TestNegEnum { None = 0, Value = -2 }
|
||||
|
||||
/*
|
||||
[Test]
|
||||
public void TestNegativeEnumArrayPacked()
|
||||
{
|
||||
int arraySize = 1 + (10 * 5);
|
||||
int msgSize = 1 + 1 + arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
output.WriteTag(8, WireFormat.WireType.LengthDelimited);
|
||||
output.WritePackedEnumArray(new RepeatedField<TestNegEnum> {
|
||||
0, (TestNegEnum) (-1), TestNegEnum.Value, (TestNegEnum) (-3), (TestNegEnum) (-4), (TestNegEnum) (-5) });
|
||||
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
uint tag;
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
List<int> values = new List<int>();
|
||||
input.ReadInt32Array(values);
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
for (int i = 0; i > -6; i--)
|
||||
Assert.AreEqual(i, values[Math.Abs(i)]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumArray()
|
||||
{
|
||||
int arraySize = 1 + 1 + (11 * 5);
|
||||
int msgSize = arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
output.WriteEnumArray(8, new RepeatedField<TestNegEnum> {
|
||||
0, (TestNegEnum) (-1), TestNegEnum.Value, (TestNegEnum) (-3), (TestNegEnum) (-4), (TestNegEnum) (-5) });
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
uint tag;
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
List<int> values = new List<int>();
|
||||
input.ReadInt32Array(values);
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
for (int i = 0; i > -6; i--)
|
||||
Assert.AreEqual(i, values[Math.Abs(i)]);
|
||||
}
|
||||
*/
|
||||
|
||||
[Test]
|
||||
public void TestCodedInputOutputPosition()
|
||||
{
|
||||
@ -407,7 +336,7 @@ namespace Google.Protobuf
|
||||
Assert.AreEqual(130, cout.Position);
|
||||
cout.Flush();
|
||||
}
|
||||
//Now test Input stream:
|
||||
// Now test Input stream:
|
||||
{
|
||||
CodedInputStream cin = CodedInputStream.CreateInstance(new MemoryStream(bytes), new byte[50]);
|
||||
uint tag;
|
||||
@ -420,8 +349,8 @@ namespace Google.Protobuf
|
||||
//Field 2:
|
||||
Assert.IsTrue(cin.ReadTag(out tag) && tag >> 3 == 2);
|
||||
Assert.AreEqual(4, cin.Position);
|
||||
uint childlen = cin.ReadRawVarint32();
|
||||
Assert.AreEqual(120u, childlen);
|
||||
int childlen = cin.ReadLength();
|
||||
Assert.AreEqual(120, childlen);
|
||||
Assert.AreEqual(5, cin.Position);
|
||||
int oldlimit = cin.PushLimit((int)childlen);
|
||||
Assert.AreEqual(5, cin.Position);
|
||||
|
@ -1,5 +1,39 @@
|
||||
using System;
|
||||
#region Copyright notice and license
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -89,5 +123,260 @@ namespace Google.Protobuf.Collections
|
||||
var clone = list.Clone();
|
||||
clone[0] = 1;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEntriesFrom_PackedInt32()
|
||||
{
|
||||
uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
var length = CodedOutputStream.ComputeInt32Size(10)
|
||||
+ CodedOutputStream.ComputeInt32Size(999)
|
||||
+ CodedOutputStream.ComputeInt32Size(-1000);
|
||||
output.WriteTag(packedTag);
|
||||
output.WriteRawVarint32((uint) length);
|
||||
output.WriteInt32(10);
|
||||
output.WriteInt32(999);
|
||||
output.WriteInt32(-1000);
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
// Deliberately "expecting" a non-packed tag, but we detect that the data is
|
||||
// actually packed.
|
||||
uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var field = new RepeatedField<int>();
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(packedTag);
|
||||
field.AddEntriesFrom(input, FieldCodec.ForInt32(nonPackedTag));
|
||||
CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEntriesFrom_NonPackedInt32()
|
||||
{
|
||||
uint nonPackedTag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
output.WriteTag(nonPackedTag);
|
||||
output.WriteInt32(10);
|
||||
output.WriteTag(nonPackedTag);
|
||||
output.WriteInt32(999);
|
||||
output.WriteTag(nonPackedTag);
|
||||
output.WriteInt32(-1000); // Just for variety...
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
// Deliberately "expecting" a packed tag, but we detect that the data is
|
||||
// actually not packed.
|
||||
uint packedTag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var field = new RepeatedField<int>();
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(nonPackedTag);
|
||||
field.AddEntriesFrom(input, FieldCodec.ForInt32(packedTag));
|
||||
CollectionAssert.AreEqual(new[] { 10, 999, -1000 }, field);
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEntriesFrom_String()
|
||||
{
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
output.WriteTag(tag);
|
||||
output.WriteString("Foo");
|
||||
output.WriteTag(tag);
|
||||
output.WriteString("");
|
||||
output.WriteTag(tag);
|
||||
output.WriteString("Bar");
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var field = new RepeatedField<string>();
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
field.AddEntriesFrom(input, FieldCodec.ForString(tag));
|
||||
CollectionAssert.AreEqual(new[] { "Foo", "", "Bar" }, field);
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddEntriesFrom_Message()
|
||||
{
|
||||
var message1 = new ForeignMessage { C = 2000 };
|
||||
var message2 = new ForeignMessage { C = -250 };
|
||||
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
output.WriteTag(tag);
|
||||
output.WriteMessage(message1);
|
||||
output.WriteTag(tag);
|
||||
output.WriteMessage(message2);
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var field = new RepeatedField<ForeignMessage>();
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
field.AddEntriesFrom(input, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
|
||||
CollectionAssert.AreEqual(new[] { message1, message2}, field);
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteTo_PackedInt32()
|
||||
{
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var field = new RepeatedField<int> { 10, 1000, 1000000 };
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
field.WriteTo(output, FieldCodec.ForInt32(tag));
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
var length = input.ReadLength();
|
||||
Assert.AreEqual(10, input.ReadInt32());
|
||||
Assert.AreEqual(1000, input.ReadInt32());
|
||||
Assert.AreEqual(1000000, input.ReadInt32());
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
Assert.AreEqual(1 + CodedOutputStream.ComputeLengthSize(length) + length, stream.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteTo_NonPackedInt32()
|
||||
{
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.Varint);
|
||||
var field = new RepeatedField<int> { 10, 1000, 1000000};
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
field.WriteTo(output, FieldCodec.ForInt32(tag));
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual(10, input.ReadInt32());
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual(1000, input.ReadInt32());
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual(1000000, input.ReadInt32());
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteTo_String()
|
||||
{
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var field = new RepeatedField<string> { "Foo", "", "Bar" };
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
field.WriteTo(output, FieldCodec.ForString(tag));
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual("Foo", input.ReadString());
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual("", input.ReadString());
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual("Bar", input.ReadString());
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteTo_Message()
|
||||
{
|
||||
var message1 = new ForeignMessage { C = 20 };
|
||||
var message2 = new ForeignMessage { C = 25 };
|
||||
uint tag = WireFormat.MakeTag(10, WireFormat.WireType.LengthDelimited);
|
||||
var field = new RepeatedField<ForeignMessage> { message1, message2 };
|
||||
var stream = new MemoryStream();
|
||||
var output = CodedOutputStream.CreateInstance(stream);
|
||||
field.WriteTo(output, FieldCodec.ForMessage(tag, ForeignMessage.Parser));
|
||||
output.Flush();
|
||||
stream.Position = 0;
|
||||
|
||||
var input = CodedInputStream.CreateInstance(stream);
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual(message1, input.ReadMessage(ForeignMessage.Parser));
|
||||
input.AssertNextTag(tag);
|
||||
Assert.AreEqual(message2, input.ReadMessage(ForeignMessage.Parser));
|
||||
Assert.IsTrue(input.IsAtEnd);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumArray()
|
||||
{
|
||||
int arraySize = 1 + 1 + (11 * 5);
|
||||
int msgSize = arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
uint tag = WireFormat.MakeTag(8, WireFormat.WireType.Varint);
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
output.WriteTag(tag);
|
||||
output.WriteEnum(i);
|
||||
}
|
||||
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
|
||||
values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
Assert.AreEqual(SampleEnum.None, values[0]);
|
||||
Assert.AreEqual(((SampleEnum)(-1)), values[1]);
|
||||
Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
|
||||
Assert.AreEqual(((SampleEnum)(-3)), values[3]);
|
||||
Assert.AreEqual(((SampleEnum)(-4)), values[4]);
|
||||
Assert.AreEqual(((SampleEnum)(-5)), values[5]);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestNegativeEnumPackedArray()
|
||||
{
|
||||
int arraySize = 1 + (10 * 5);
|
||||
int msgSize = 1 + 1 + arraySize;
|
||||
byte[] bytes = new byte[msgSize];
|
||||
CodedOutputStream output = CodedOutputStream.CreateInstance(bytes);
|
||||
// Length-delimited to show we want the packed representation
|
||||
uint tag = WireFormat.MakeTag(8, WireFormat.WireType.LengthDelimited);
|
||||
output.WriteTag(tag);
|
||||
int size = 0;
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
size += CodedOutputStream.ComputeEnumSize(i);
|
||||
}
|
||||
output.WriteRawVarint32((uint)size);
|
||||
for (int i = 0; i >= -5; i--)
|
||||
{
|
||||
output.WriteEnum(i);
|
||||
}
|
||||
Assert.AreEqual(0, output.SpaceLeft);
|
||||
|
||||
CodedInputStream input = CodedInputStream.CreateInstance(bytes);
|
||||
Assert.IsTrue(input.ReadTag(out tag));
|
||||
|
||||
RepeatedField<SampleEnum> values = new RepeatedField<SampleEnum>();
|
||||
values.AddEntriesFrom(input, FieldCodec.ForEnum(tag, x => (int)x, x => (SampleEnum)x));
|
||||
|
||||
Assert.AreEqual(6, values.Count);
|
||||
Assert.AreEqual(SampleEnum.None, values[0]);
|
||||
Assert.AreEqual(((SampleEnum)(-1)), values[1]);
|
||||
Assert.AreEqual(SampleEnum.NegativeValue, values[2]);
|
||||
Assert.AreEqual(((SampleEnum)(-3)), values[3]);
|
||||
Assert.AreEqual(((SampleEnum)(-4)), values[4]);
|
||||
Assert.AreEqual(((SampleEnum)(-5)), values[5]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,15 +63,21 @@ namespace Google.Protobuf
|
||||
};
|
||||
|
||||
[Test, TestCaseSource("Codecs")]
|
||||
public void RoundTrip(ICodecTestData codec)
|
||||
public void RoundTripWithTag(ICodecTestData codec)
|
||||
{
|
||||
codec.TestRoundTrip();
|
||||
codec.TestRoundTripWithTag();
|
||||
}
|
||||
|
||||
[Test, TestCaseSource("Codecs")]
|
||||
public void RoundTripRaw(ICodecTestData codec)
|
||||
{
|
||||
codec.TestRoundTripRaw();
|
||||
}
|
||||
|
||||
[Test, TestCaseSource("Codecs")]
|
||||
public void CalculateSize(ICodecTestData codec)
|
||||
{
|
||||
codec.TestCalculateSize();
|
||||
codec.TestCalculateSizeWithTag();
|
||||
}
|
||||
|
||||
[Test, TestCaseSource("Codecs")]
|
||||
@ -82,8 +88,9 @@ namespace Google.Protobuf
|
||||
|
||||
public interface ICodecTestData
|
||||
{
|
||||
void TestRoundTrip();
|
||||
void TestCalculateSize();
|
||||
void TestRoundTripRaw();
|
||||
void TestRoundTripWithTag();
|
||||
void TestCalculateSizeWithTag();
|
||||
void TestDefaultValue();
|
||||
}
|
||||
|
||||
@ -100,7 +107,19 @@ namespace Google.Protobuf
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void TestRoundTrip()
|
||||
public void TestRoundTripRaw()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var codedOutput = CodedOutputStream.CreateInstance(stream);
|
||||
codec.ValueWriter(codedOutput, sampleValue);
|
||||
codedOutput.Flush();
|
||||
stream.Position = 0;
|
||||
var codedInput = CodedInputStream.CreateInstance(stream);
|
||||
Assert.AreEqual(sampleValue, codec.ValueReader(codedInput));
|
||||
Assert.IsTrue(codedInput.IsAtEnd);
|
||||
}
|
||||
|
||||
public void TestRoundTripWithTag()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var codedOutput = CodedOutputStream.CreateInstance(stream);
|
||||
@ -108,14 +127,12 @@ namespace Google.Protobuf
|
||||
codedOutput.Flush();
|
||||
stream.Position = 0;
|
||||
var codedInput = CodedInputStream.CreateInstance(stream);
|
||||
uint tag;
|
||||
Assert.IsTrue(codedInput.ReadTag(out tag));
|
||||
Assert.AreEqual(codec.Tag, tag);
|
||||
codedInput.AssertNextTag(codec.Tag);
|
||||
Assert.AreEqual(sampleValue, codec.Read(codedInput));
|
||||
Assert.IsTrue(codedInput.IsAtEnd);
|
||||
}
|
||||
|
||||
public void TestCalculateSize()
|
||||
public void TestCalculateSizeWithTag()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var codedOutput = CodedOutputStream.CreateInstance(stream);
|
||||
@ -126,6 +143,7 @@ namespace Google.Protobuf
|
||||
|
||||
public void TestDefaultValue()
|
||||
{
|
||||
// WriteTagAndValue ignores default values
|
||||
var stream = new MemoryStream();
|
||||
var codedOutput = CodedOutputStream.CreateInstance(stream);
|
||||
codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
|
||||
@ -136,9 +154,20 @@ namespace Google.Protobuf
|
||||
{
|
||||
Assert.AreEqual(default(T), codec.DefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
public string Description { get { return name; } }
|
||||
// The plain ValueWriter/ValueReader delegates don't.
|
||||
if (codec.DefaultValue != null) // This part isn't appropriate for message types.
|
||||
{
|
||||
codedOutput = CodedOutputStream.CreateInstance(stream);
|
||||
codec.ValueWriter(codedOutput, codec.DefaultValue);
|
||||
codedOutput.Flush();
|
||||
Assert.AreNotEqual(0, stream.Position);
|
||||
Assert.AreEqual(stream.Position, codec.ValueSizeCalculator(codec.DefaultValue));
|
||||
stream.Position = 0;
|
||||
var codedInput = CodedInputStream.CreateInstance(stream);
|
||||
Assert.AreEqual(codec.DefaultValue, codec.ValueReader(codedInput));
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -10,6 +10,61 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public class GeneratedMessageTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a sample TestAllTypes with all fields populated
|
||||
/// </summary>
|
||||
public static TestAllTypes GetSampleMessage()
|
||||
{
|
||||
return new TestAllTypes
|
||||
{
|
||||
SingleBool = true,
|
||||
SingleBytes = ByteString.CopyFrom(1, 2, 3, 4),
|
||||
SingleDouble = 23.5,
|
||||
SingleFixed32 = 23,
|
||||
SingleFixed64 = 1234567890123,
|
||||
SingleFloat = 12.25f,
|
||||
SingleForeignEnum = ForeignEnum.FOREIGN_BAR,
|
||||
SingleForeignMessage = new ForeignMessage { C = 10 },
|
||||
SingleImportEnum = ImportEnum.IMPORT_BAZ,
|
||||
SingleImportMessage = new ImportMessage { D = 20 },
|
||||
SingleInt32 = 100,
|
||||
SingleInt64 = 3210987654321,
|
||||
SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO,
|
||||
SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 },
|
||||
SinglePublicImportMessage = new PublicImportMessage { E = 54 },
|
||||
SingleSfixed32 = -123,
|
||||
SingleSfixed64 = -12345678901234,
|
||||
SingleSint32 = -456,
|
||||
SingleSint64 = -12345678901235,
|
||||
SingleString = "test",
|
||||
SingleUint32 = uint.MaxValue,
|
||||
SingleUint64 = ulong.MaxValue,
|
||||
RepeatedBool = { true, false },
|
||||
RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6), ByteString.CopyFrom(new byte[1000]) },
|
||||
RepeatedDouble = { -12.25, 23.5 },
|
||||
RepeatedFixed32 = { uint.MaxValue, 23 },
|
||||
RepeatedFixed64 = { ulong.MaxValue, 1234567890123 },
|
||||
RepeatedFloat = { 100f, 12.25f },
|
||||
RepeatedForeignEnum = { ForeignEnum.FOREIGN_FOO, ForeignEnum.FOREIGN_BAR },
|
||||
RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } },
|
||||
RepeatedImportEnum = { ImportEnum.IMPORT_BAZ, ImportEnum.IMPORT_ENUM_UNSPECIFIED },
|
||||
RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } },
|
||||
RepeatedInt32 = { 100, 200 },
|
||||
RepeatedInt64 = { 3210987654321, long.MaxValue },
|
||||
RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG },
|
||||
RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } },
|
||||
RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } },
|
||||
RepeatedSfixed32 = { -123, 123 },
|
||||
RepeatedSfixed64 = { -12345678901234, 12345678901234 },
|
||||
RepeatedSint32 = { -456, 100 },
|
||||
RepeatedSint64 = { -12345678901235, 123 },
|
||||
RepeatedString = { "foo", "bar" },
|
||||
RepeatedUint32 = { uint.MaxValue, uint.MinValue },
|
||||
RepeatedUint64 = { ulong.MaxValue, uint.MinValue },
|
||||
OneofString = "Oneof string"
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyMessageFieldDistinctFromMissingMessageField()
|
||||
{
|
||||
@ -485,5 +540,83 @@ namespace Google.Protobuf
|
||||
Assert.Throws<InvalidOperationException>(() => frozen.RepeatedDouble.Add(0.0));
|
||||
Assert.Throws<InvalidOperationException>(() => frozen.RepeatedNestedMessage.Add(new TestAllTypes.Types.NestedMessage()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneofProperties()
|
||||
{
|
||||
// Switch the oneof case between each of the different options, and check everything behaves
|
||||
// as expected in each case.
|
||||
var message = new TestAllTypes();
|
||||
Assert.AreEqual("", message.OneofString);
|
||||
Assert.AreEqual(0, message.OneofUint32);
|
||||
Assert.AreEqual(ByteString.Empty, message.OneofBytes);
|
||||
Assert.IsNull(message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
|
||||
|
||||
message.OneofString = "sample";
|
||||
Assert.AreEqual("sample", message.OneofString);
|
||||
Assert.AreEqual(0, message.OneofUint32);
|
||||
Assert.AreEqual(ByteString.Empty, message.OneofBytes);
|
||||
Assert.IsNull(message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase);
|
||||
|
||||
var bytes = ByteString.CopyFrom(1, 2, 3);
|
||||
message.OneofBytes = bytes;
|
||||
Assert.AreEqual("", message.OneofString);
|
||||
Assert.AreEqual(0, message.OneofUint32);
|
||||
Assert.AreEqual(bytes, message.OneofBytes);
|
||||
Assert.IsNull(message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase);
|
||||
|
||||
message.OneofUint32 = 20;
|
||||
Assert.AreEqual("", message.OneofString);
|
||||
Assert.AreEqual(20, message.OneofUint32);
|
||||
Assert.AreEqual(ByteString.Empty, message.OneofBytes);
|
||||
Assert.IsNull(message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase);
|
||||
|
||||
var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 };
|
||||
message.OneofNestedMessage = nestedMessage;
|
||||
Assert.AreEqual("", message.OneofString);
|
||||
Assert.AreEqual(0, message.OneofUint32);
|
||||
Assert.AreEqual(ByteString.Empty, message.OneofBytes);
|
||||
Assert.AreEqual(nestedMessage, message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase);
|
||||
|
||||
message.ClearOneofField();
|
||||
Assert.AreEqual("", message.OneofString);
|
||||
Assert.AreEqual(0, message.OneofUint32);
|
||||
Assert.AreEqual(ByteString.Empty, message.OneofBytes);
|
||||
Assert.IsNull(message.OneofNestedMessage);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneofSerialization_NonDefaultValue()
|
||||
{
|
||||
var message = new TestAllTypes();
|
||||
message.OneofString = "this would take a bit of space";
|
||||
message.OneofUint32 = 10;
|
||||
var bytes = message.ToByteArray();
|
||||
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string!
|
||||
|
||||
var message2 = TestAllTypes.Parser.ParseFrom(bytes);
|
||||
Assert.AreEqual(message, message2);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneofSerialization_DefaultValue()
|
||||
{
|
||||
var message = new TestAllTypes();
|
||||
message.OneofString = "this would take a bit of space";
|
||||
message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized
|
||||
var bytes = message.ToByteArray();
|
||||
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized
|
||||
|
||||
var message2 = TestAllTypes.Parser.ParseFrom(bytes);
|
||||
Assert.AreEqual(message, message2);
|
||||
Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ByteStringTest.cs" />
|
||||
<Compile Include="CodedInputStreamExtensions.cs" />
|
||||
<Compile Include="CodedInputStreamTest.cs" />
|
||||
<Compile Include="CodedOutputStreamTest.cs" />
|
||||
<Compile Include="EqualityTester.cs" />
|
||||
@ -79,6 +80,7 @@
|
||||
<Compile Include="GeneratedMessageTest.cs" />
|
||||
<Compile Include="Collections\MapFieldTest.cs" />
|
||||
<Compile Include="Collections\RepeatedFieldTest.cs" />
|
||||
<Compile Include="SampleEnum.cs" />
|
||||
<Compile Include="TestProtos\MapUnittestProto3.cs" />
|
||||
<Compile Include="TestProtos\UnittestImportProto3.cs" />
|
||||
<Compile Include="TestProtos\UnittestImportPublicProto3.cs" />
|
||||
|
42
csharp/src/ProtocolBuffers.Test/SampleEnum.cs
Normal file
42
csharp/src/ProtocolBuffers.Test/SampleEnum.cs
Normal file
@ -0,0 +1,42 @@
|
||||
#region Copyright notice and license
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
namespace Google.Protobuf
|
||||
{
|
||||
// Just a sample enum with positive and negative values to be used in tests.
|
||||
internal enum SampleEnum
|
||||
{
|
||||
NegativeValue = -2,
|
||||
None = 0,
|
||||
PositiveValue = 3
|
||||
}
|
||||
}
|
@ -37,7 +37,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Google.Protobuf.Collections;
|
||||
|
||||
namespace Google.Protobuf
|
||||
{
|
||||
@ -178,8 +177,61 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
internal uint LastTag { get { return lastTag; } }
|
||||
|
||||
#region Validation
|
||||
#region Limits for recursion and length
|
||||
/// <summary>
|
||||
/// Set the maximum message recursion depth.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to prevent malicious
|
||||
/// messages from causing stack overflows, CodedInputStream limits
|
||||
/// how deeply messages may be nested. The default limit is 64.
|
||||
/// </remarks>
|
||||
public int SetRecursionLimit(int limit)
|
||||
{
|
||||
if (limit < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);
|
||||
}
|
||||
int oldLimit = recursionLimit;
|
||||
recursionLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the maximum message size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to prevent malicious messages from exhausting memory or
|
||||
/// causing integer overflows, CodedInputStream limits how large a message may be.
|
||||
/// The default limit is 64MB. You should set this limit as small
|
||||
/// as you can without harming your app's functionality. Note that
|
||||
/// size limits only apply when reading from an InputStream, not
|
||||
/// when constructed around a raw byte array (nor with ByteString.NewCodedInput).
|
||||
/// If you want to read several messages from a single CodedInputStream, you
|
||||
/// can call ResetSizeCounter() after each message to avoid hitting the
|
||||
/// size limit.
|
||||
/// </remarks>
|
||||
public int SetSizeLimit(int limit)
|
||||
{
|
||||
if (limit < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);
|
||||
}
|
||||
int oldLimit = sizeLimit;
|
||||
sizeLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current size counter to zero (see <see cref="SetSizeLimit"/>).
|
||||
/// </summary>
|
||||
public void ResetSizeCounter()
|
||||
{
|
||||
totalBytesRetired = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Validation
|
||||
/// <summary>
|
||||
/// Verifies that the last call to ReadTag() returned the given tag value.
|
||||
/// This is used to verify that a nested group ended with the correct
|
||||
@ -194,13 +246,12 @@ namespace Google.Protobuf
|
||||
throw InvalidProtocolBufferException.InvalidEndTag();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reading of tags etc
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to peek at the next field tag.
|
||||
/// Attempts to peek at the next field tag.
|
||||
/// </summary>
|
||||
public bool PeekNextTag(out uint fieldTag)
|
||||
{
|
||||
@ -218,7 +269,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to read a field tag, returning false if we have reached the end
|
||||
/// Attempts to read a field tag, returning false if we have reached the end
|
||||
/// of the input data.
|
||||
/// </summary>
|
||||
/// <param name="fieldTag">The 'tag' of the field (id * 8 + wire-format)</param>
|
||||
@ -233,14 +284,42 @@ namespace Google.Protobuf
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAtEnd)
|
||||
// Optimize for the incredibly common case of having at least two bytes left in the buffer,
|
||||
// and those two bytes being enough to get the tag. This will be true for fields up to 4095.
|
||||
if (bufferPos + 2 <= bufferSize)
|
||||
{
|
||||
fieldTag = 0;
|
||||
lastTag = fieldTag;
|
||||
return false;
|
||||
int tmp = buffer[bufferPos++];
|
||||
if (tmp < 128)
|
||||
{
|
||||
fieldTag = (uint)tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
int result = tmp & 0x7f;
|
||||
if ((tmp = buffer[bufferPos++]) < 128)
|
||||
{
|
||||
result |= tmp << 7;
|
||||
fieldTag = (uint) result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nope, rewind and go the potentially slow route.
|
||||
bufferPos -= 2;
|
||||
fieldTag = ReadRawVarint32();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsAtEnd)
|
||||
{
|
||||
fieldTag = 0;
|
||||
lastTag = fieldTag;
|
||||
return false;
|
||||
}
|
||||
|
||||
fieldTag = ReadRawVarint32();
|
||||
fieldTag = ReadRawVarint32();
|
||||
}
|
||||
lastTag = fieldTag;
|
||||
if (lastTag == 0)
|
||||
{
|
||||
@ -251,7 +330,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a double field from the stream.
|
||||
/// Reads a double field from the stream.
|
||||
/// </summary>
|
||||
public double ReadDouble()
|
||||
{
|
||||
@ -259,7 +338,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a float field from the stream.
|
||||
/// Reads a float field from the stream.
|
||||
/// </summary>
|
||||
public float ReadFloat()
|
||||
{
|
||||
@ -281,7 +360,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a uint64 field from the stream.
|
||||
/// Reads a uint64 field from the stream.
|
||||
/// </summary>
|
||||
public ulong ReadUInt64()
|
||||
{
|
||||
@ -289,7 +368,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int64 field from the stream.
|
||||
/// Reads an int64 field from the stream.
|
||||
/// </summary>
|
||||
public long ReadInt64()
|
||||
{
|
||||
@ -297,7 +376,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int32 field from the stream.
|
||||
/// Reads an int32 field from the stream.
|
||||
/// </summary>
|
||||
public int ReadInt32()
|
||||
{
|
||||
@ -305,7 +384,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a fixed64 field from the stream.
|
||||
/// Reads a fixed64 field from the stream.
|
||||
/// </summary>
|
||||
public ulong ReadFixed64()
|
||||
{
|
||||
@ -313,7 +392,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a fixed32 field from the stream.
|
||||
/// Reads a fixed32 field from the stream.
|
||||
/// </summary>
|
||||
public uint ReadFixed32()
|
||||
{
|
||||
@ -321,7 +400,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a bool field from the stream.
|
||||
/// Reads a bool field from the stream.
|
||||
/// </summary>
|
||||
public bool ReadBool()
|
||||
{
|
||||
@ -333,22 +412,22 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public string ReadString()
|
||||
{
|
||||
int size = (int) ReadRawVarint32();
|
||||
int length = ReadLength();
|
||||
// No need to read any data for an empty string.
|
||||
if (size == 0)
|
||||
if (length == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (size <= bufferSize - bufferPos)
|
||||
if (length <= bufferSize - bufferPos)
|
||||
{
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, size);
|
||||
bufferPos += size;
|
||||
String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
|
||||
bufferPos += length;
|
||||
return result;
|
||||
}
|
||||
// Slow path: Build a byte array first then copy it.
|
||||
return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(size), 0, size);
|
||||
return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -356,7 +435,7 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public void ReadMessage(IMessage builder)
|
||||
{
|
||||
int length = (int) ReadRawVarint32();
|
||||
int length = ReadLength();
|
||||
if (recursionDepth >= recursionLimit)
|
||||
{
|
||||
throw InvalidProtocolBufferException.RecursionLimitExceeded();
|
||||
@ -374,19 +453,19 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public ByteString ReadBytes()
|
||||
{
|
||||
int size = (int) ReadRawVarint32();
|
||||
if (size <= bufferSize - bufferPos && size > 0)
|
||||
int length = ReadLength();
|
||||
if (length <= bufferSize - bufferPos && length > 0)
|
||||
{
|
||||
// Fast path: We already have the bytes in a contiguous buffer, so
|
||||
// just copy directly from it.
|
||||
ByteString result = ByteString.CopyFrom(buffer, bufferPos, size);
|
||||
bufferPos += size;
|
||||
ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
|
||||
bufferPos += length;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slow path: Build a byte array and attach it to a new ByteString.
|
||||
return ByteString.AttachBytes(ReadRawBytes(size));
|
||||
return ByteString.AttachBytes(ReadRawBytes(length));
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,6 +520,18 @@ namespace Google.Protobuf
|
||||
return DecodeZigZag64(ReadRawVarint64());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a length for length-delimited data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is internally just reading a varint, but this method exists
|
||||
/// to make the calling code clearer.
|
||||
/// </remarks>
|
||||
public int ReadLength()
|
||||
{
|
||||
return (int) ReadRawVarint32();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
|
||||
/// the tag is consumed and the method returns <c>true</c>; otherwise, the
|
||||
@ -517,12 +608,12 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
|
||||
/// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
|
||||
/// This method is optimised for the case where we've got lots of data in the buffer.
|
||||
/// That means we can check the size just once, then just read directly from the buffer
|
||||
/// without constant rechecking of the buffer length.
|
||||
/// </summary>
|
||||
public uint ReadRawVarint32()
|
||||
internal uint ReadRawVarint32()
|
||||
{
|
||||
if (bufferPos + 5 > bufferSize)
|
||||
{
|
||||
@ -581,13 +672,13 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Reads a varint from the input one byte at a time, so that it does not
|
||||
/// read any bytes after the end of the varint. If you simply wrapped the
|
||||
/// stream in a CodedInputStream and used ReadRawVarint32(Stream)}
|
||||
/// stream in a CodedInputStream and used ReadRawVarint32(Stream)
|
||||
/// then you would probably end up reading past the end of the varint since
|
||||
/// CodedInputStream buffers its input.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static uint ReadRawVarint32(Stream input)
|
||||
internal static uint ReadRawVarint32(Stream input)
|
||||
{
|
||||
int result = 0;
|
||||
int offset = 0;
|
||||
@ -621,9 +712,9 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a raw varint from the stream.
|
||||
/// Reads a raw varint from the stream.
|
||||
/// </summary>
|
||||
public ulong ReadRawVarint64()
|
||||
internal ulong ReadRawVarint64()
|
||||
{
|
||||
int shift = 0;
|
||||
ulong result = 0;
|
||||
@ -641,9 +732,9 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a 32-bit little-endian integer from the stream.
|
||||
/// Reads a 32-bit little-endian integer from the stream.
|
||||
/// </summary>
|
||||
public uint ReadRawLittleEndian32()
|
||||
internal uint ReadRawLittleEndian32()
|
||||
{
|
||||
uint b1 = ReadRawByte();
|
||||
uint b2 = ReadRawByte();
|
||||
@ -653,9 +744,9 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a 64-bit little-endian integer from the stream.
|
||||
/// Reads a 64-bit little-endian integer from the stream.
|
||||
/// </summary>
|
||||
public ulong ReadRawLittleEndian64()
|
||||
internal ulong ReadRawLittleEndian64()
|
||||
{
|
||||
ulong b1 = ReadRawByte();
|
||||
ulong b2 = ReadRawByte();
|
||||
@ -669,97 +760,44 @@ namespace Google.Protobuf
|
||||
| (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a 32-bit value with ZigZag encoding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ZigZag encodes signed integers into values that can be efficiently
|
||||
/// encoded with varint. (Otherwise, negative values must be
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
internal static int DecodeZigZag32(uint n)
|
||||
{
|
||||
return (int)(n >> 1) ^ -(int)(n & 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a 32-bit value with ZigZag encoding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ZigZag encodes signed integers into values that can be efficiently
|
||||
/// encoded with varint. (Otherwise, negative values must be
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
internal static long DecodeZigZag64(ulong n)
|
||||
{
|
||||
return (long)(n >> 1) ^ -(long)(n & 1);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Decode a 32-bit value with ZigZag encoding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ZigZag encodes signed integers into values that can be efficiently
|
||||
/// encoded with varint. (Otherwise, negative values must be
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
public static int DecodeZigZag32(uint n)
|
||||
{
|
||||
return (int) (n >> 1) ^ -(int) (n & 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a 32-bit value with ZigZag encoding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ZigZag encodes signed integers into values that can be efficiently
|
||||
/// encoded with varint. (Otherwise, negative values must be
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
public static long DecodeZigZag64(ulong n)
|
||||
{
|
||||
return (long) (n >> 1) ^ -(long) (n & 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the maximum message recursion depth.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to prevent malicious
|
||||
/// messages from causing stack overflows, CodedInputStream limits
|
||||
/// how deeply messages may be nested. The default limit is 64.
|
||||
/// </remarks>
|
||||
public int SetRecursionLimit(int limit)
|
||||
{
|
||||
if (limit < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);
|
||||
}
|
||||
int oldLimit = recursionLimit;
|
||||
recursionLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the maximum message size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to prevent malicious messages from exhausting memory or
|
||||
/// causing integer overflows, CodedInputStream limits how large a message may be.
|
||||
/// The default limit is 64MB. You should set this limit as small
|
||||
/// as you can without harming your app's functionality. Note that
|
||||
/// size limits only apply when reading from an InputStream, not
|
||||
/// when constructed around a raw byte array (nor with ByteString.NewCodedInput).
|
||||
/// If you want to read several messages from a single CodedInputStream, you
|
||||
/// can call ResetSizeCounter() after each message to avoid hitting the
|
||||
/// size limit.
|
||||
/// </remarks>
|
||||
public int SetSizeLimit(int limit)
|
||||
{
|
||||
if (limit < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);
|
||||
}
|
||||
int oldLimit = sizeLimit;
|
||||
sizeLimit = limit;
|
||||
return oldLimit;
|
||||
}
|
||||
|
||||
#region Internal reading and buffer management
|
||||
|
||||
/// <summary>
|
||||
/// Resets the current size counter to zero (see SetSizeLimit).
|
||||
/// </summary>
|
||||
public void ResetSizeCounter()
|
||||
{
|
||||
totalBytesRetired = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets currentLimit to (current position) + byteLimit. This is called
|
||||
/// when descending into a length-delimited embedded message. The previous
|
||||
/// limit is returned.
|
||||
/// </summary>
|
||||
/// <returns>The old limit.</returns>
|
||||
public int PushLimit(int byteLimit)
|
||||
internal int PushLimit(int byteLimit)
|
||||
{
|
||||
if (byteLimit < 0)
|
||||
{
|
||||
@ -797,7 +835,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Discards the current limit, returning the previous limit.
|
||||
/// </summary>
|
||||
public void PopLimit(int oldLimit)
|
||||
internal void PopLimit(int oldLimit)
|
||||
{
|
||||
currentLimit = oldLimit;
|
||||
RecomputeBufferSizeAfterLimit();
|
||||
@ -807,7 +845,7 @@ namespace Google.Protobuf
|
||||
/// Returns whether or not all the data before the limit has been read.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ReachedLimit
|
||||
internal bool ReachedLimit
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -897,7 +935,7 @@ namespace Google.Protobuf
|
||||
/// <exception cref="InvalidProtocolBufferException">
|
||||
/// the end of the stream or the current limit was reached
|
||||
/// </exception>
|
||||
public byte ReadRawByte()
|
||||
internal byte ReadRawByte()
|
||||
{
|
||||
if (bufferPos == bufferSize)
|
||||
{
|
||||
@ -907,12 +945,12 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a fixed size of bytes from the input.
|
||||
/// Reads a fixed size of bytes from the input.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidProtocolBufferException">
|
||||
/// the end of the stream or the current limit was reached
|
||||
/// </exception>
|
||||
public byte[] ReadRawBytes(int size)
|
||||
internal byte[] ReadRawBytes(int size)
|
||||
{
|
||||
if (size < 0)
|
||||
{
|
||||
@ -921,7 +959,8 @@ namespace Google.Protobuf
|
||||
|
||||
if (totalBytesRetired + bufferPos + size > currentLimit)
|
||||
{
|
||||
// Read to the end of the stream anyway.
|
||||
// Read to the end of the stream (up to the current limit) anyway.
|
||||
// TODO(jonskeet): This is the only usage of SkipRawBytes. Do we really need to do it?
|
||||
SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
|
||||
// Then fail.
|
||||
throw InvalidProtocolBufferException.TruncatedMessage();
|
||||
@ -1025,63 +1064,12 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads and discards a single field, given its tag value.
|
||||
/// </summary>
|
||||
/// <returns>false if the tag is an end-group tag, in which case
|
||||
/// nothing is skipped. Otherwise, returns true.</returns>
|
||||
public bool SkipField()
|
||||
{
|
||||
uint tag = lastTag;
|
||||
switch (WireFormat.GetTagWireType(tag))
|
||||
{
|
||||
case WireFormat.WireType.Varint:
|
||||
ReadRawVarint64();
|
||||
return true;
|
||||
case WireFormat.WireType.Fixed64:
|
||||
ReadRawLittleEndian64();
|
||||
return true;
|
||||
case WireFormat.WireType.LengthDelimited:
|
||||
SkipRawBytes((int) ReadRawVarint32());
|
||||
return true;
|
||||
case WireFormat.WireType.StartGroup:
|
||||
SkipMessage();
|
||||
CheckLastTagWas(
|
||||
WireFormat.MakeTag(WireFormat.GetTagFieldNumber(tag),
|
||||
WireFormat.WireType.EndGroup));
|
||||
return true;
|
||||
case WireFormat.WireType.EndGroup:
|
||||
return false;
|
||||
case WireFormat.WireType.Fixed32:
|
||||
ReadRawLittleEndian32();
|
||||
return true;
|
||||
default:
|
||||
throw InvalidProtocolBufferException.InvalidWireType();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads and discards an entire message. This will read either until EOF
|
||||
/// or until an endgroup tag, whichever comes first.
|
||||
/// </summary>
|
||||
public void SkipMessage()
|
||||
{
|
||||
uint tag;
|
||||
while (ReadTag(out tag))
|
||||
{
|
||||
if (!SkipField())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads and discards <paramref name="size"/> bytes.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidProtocolBufferException">the end of the stream
|
||||
/// or the current limit was reached</exception>
|
||||
public void SkipRawBytes(int size)
|
||||
private void SkipRawBytes(int size)
|
||||
{
|
||||
if (size < 0)
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace Google.Protobuf
|
||||
private const int LittleEndian32Size = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// double field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeDoubleSize(double value)
|
||||
@ -59,7 +59,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// float field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeFloatSize(float value)
|
||||
@ -68,7 +68,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// uint64 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeUInt64Size(ulong value)
|
||||
@ -77,7 +77,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// int64 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeInt64Size(long value)
|
||||
@ -86,7 +86,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// int32 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeInt32Size(int value)
|
||||
@ -103,7 +103,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// fixed64 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeFixed64Size(ulong value)
|
||||
@ -112,7 +112,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// fixed32 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeFixed32Size(uint value)
|
||||
@ -121,7 +121,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// bool field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeBoolSize(bool value)
|
||||
@ -130,7 +130,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// string field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeStringSize(String value)
|
||||
@ -141,7 +141,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// group field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeGroupSize(IMessage value)
|
||||
@ -150,7 +150,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// embedded message field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeMessageSize(IMessage value)
|
||||
@ -160,7 +160,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// bytes field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeBytesSize(ByteString value)
|
||||
@ -170,7 +170,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes the number of bytes that would be needed to encode a
|
||||
/// uint32 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeUInt32Size(uint value)
|
||||
@ -179,7 +179,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a
|
||||
/// Computes 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>
|
||||
@ -190,7 +190,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// sfixed32 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeSFixed32Size(int value)
|
||||
@ -199,7 +199,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// sfixed64 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeSFixed64Size(long value)
|
||||
@ -208,7 +208,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// sint32 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeSInt32Size(int value)
|
||||
@ -217,7 +217,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode an
|
||||
/// Computes the number of bytes that would be needed to encode an
|
||||
/// sint64 field, including the tag.
|
||||
/// </summary>
|
||||
public static int ComputeSInt64Size(long value)
|
||||
@ -226,7 +226,16 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a varint.
|
||||
/// Computes the number of bytes that would be needed to encode a length,
|
||||
/// as written by <see cref="WriteLength"/>.
|
||||
/// </summary>
|
||||
public static int ComputeLengthSize(int length)
|
||||
{
|
||||
return ComputeRawVarint32Size((uint) length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the number of bytes that would be needed to encode a varint.
|
||||
/// </summary>
|
||||
public static int ComputeRawVarint32Size(uint value)
|
||||
{
|
||||
@ -250,7 +259,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a varint.
|
||||
/// Computes the number of bytes that would be needed to encode a varint.
|
||||
/// </summary>
|
||||
public static int ComputeRawVarint64Size(ulong value)
|
||||
{
|
||||
@ -294,7 +303,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the number of bytes that would be needed to encode a tag.
|
||||
/// Computes the number of bytes that would be needed to encode a tag.
|
||||
/// </summary>
|
||||
public static int ComputeTagSize(int fieldNumber)
|
||||
{
|
||||
|
@ -37,7 +37,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Google.Protobuf.Collections;
|
||||
|
||||
namespace Google.Protobuf
|
||||
{
|
||||
@ -141,11 +140,12 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
#region Writing of values without tags
|
||||
#region Writing of values (not including tags)
|
||||
|
||||
/// <summary>
|
||||
/// Writes a double field value, including tag, to the stream.
|
||||
/// Writes a double field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteDouble(double value)
|
||||
{
|
||||
WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
|
||||
@ -154,6 +154,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes a float field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteFloat(float value)
|
||||
{
|
||||
byte[] rawBytes = BitConverter.GetBytes(value);
|
||||
@ -178,6 +179,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes a uint64 field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteUInt64(ulong value)
|
||||
{
|
||||
WriteRawVarint64(value);
|
||||
@ -186,6 +188,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes an int64 field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteInt64(long value)
|
||||
{
|
||||
WriteRawVarint64((ulong) value);
|
||||
@ -194,6 +197,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes an int32 field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteInt32(int value)
|
||||
{
|
||||
if (value >= 0)
|
||||
@ -210,6 +214,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes a fixed64 field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteFixed64(ulong value)
|
||||
{
|
||||
WriteRawLittleEndian64(value);
|
||||
@ -218,6 +223,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes a fixed32 field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteFixed32(uint value)
|
||||
{
|
||||
WriteRawLittleEndian32(value);
|
||||
@ -226,6 +232,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes a bool field value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteBool(bool value)
|
||||
{
|
||||
WriteRawByte(value ? (byte) 1 : (byte) 0);
|
||||
@ -233,13 +240,15 @@ namespace Google.Protobuf
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string field value, without a tag, to the stream.
|
||||
/// The data is length-prefixed.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteString(string value)
|
||||
{
|
||||
// Optimise the case where we have enough space to write
|
||||
// the string directly to the buffer, which should be common.
|
||||
int length = Utf8Encoding.GetByteCount(value);
|
||||
WriteRawVarint32((uint)length);
|
||||
WriteLength(length);
|
||||
if (limit - position >= length)
|
||||
{
|
||||
if (length == value.Length) // Must be all ASCII...
|
||||
@ -262,23 +271,41 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a message, without a tag, to the stream.
|
||||
/// The data is length-prefixed.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteMessage(IMessage value)
|
||||
{
|
||||
WriteRawVarint32((uint) value.CalculateSize());
|
||||
value.WriteTo(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte string, without a tag, to the stream.
|
||||
/// The data is length-prefixed.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteBytes(ByteString value)
|
||||
{
|
||||
WriteRawVarint32((uint) value.Length);
|
||||
value.WriteRawBytesTo(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a uint32 value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteUInt32(uint value)
|
||||
{
|
||||
WriteRawVarint32(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an enum value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteEnum(int value)
|
||||
{
|
||||
WriteInt32(value);
|
||||
@ -289,27 +316,53 @@ namespace Google.Protobuf
|
||||
WriteRawLittleEndian32((uint) value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an sfixed64 value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteSFixed64(long value)
|
||||
{
|
||||
WriteRawLittleEndian64((ulong) value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an sint32 value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteSInt32(int value)
|
||||
{
|
||||
WriteRawVarint32(EncodeZigZag32(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an sint64 value, without a tag, to the stream.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to write</param>
|
||||
public void WriteSInt64(long value)
|
||||
{
|
||||
WriteRawVarint64(EncodeZigZag64(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a length (in bytes) for length-delimited data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method simply writes a rawint, but exists for clarity in calling code.
|
||||
/// </remarks>
|
||||
/// <param name="length">Length value, in bytes.</param>
|
||||
public void WriteLength(int length)
|
||||
{
|
||||
WriteRawVarint32((uint) length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Raw tag writing
|
||||
/// <summary>
|
||||
/// Encodes and writes a tag.
|
||||
/// </summary>
|
||||
/// <param name="fieldNumber">The number of the field to write the tag for</param>
|
||||
/// <param name="type">The wire format type of the tag to write</param>
|
||||
public void WriteTag(int fieldNumber, WireFormat.WireType type)
|
||||
{
|
||||
WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
|
||||
@ -318,6 +371,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes an already-encoded tag.
|
||||
/// </summary>
|
||||
/// <param name="tag">The encoded tag</param>
|
||||
public void WriteTag(uint tag)
|
||||
{
|
||||
WriteRawVarint32(tag);
|
||||
@ -326,6 +380,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes the given single-byte tag directly to the stream.
|
||||
/// </summary>
|
||||
/// <param name="b1">The encoded tag</param>
|
||||
public void WriteRawTag(byte b1)
|
||||
{
|
||||
WriteRawByte(b1);
|
||||
@ -334,6 +389,8 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes the given two-byte tag directly to the stream.
|
||||
/// </summary>
|
||||
/// <param name="b1">The first byte of the encoded tag</param>
|
||||
/// <param name="b2">The second byte of the encoded tag</param>
|
||||
public void WriteRawTag(byte b1, byte b2)
|
||||
{
|
||||
WriteRawByte(b1);
|
||||
@ -343,6 +400,9 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes the given three-byte tag directly to the stream.
|
||||
/// </summary>
|
||||
/// <param name="b1">The first byte of the encoded tag</param>
|
||||
/// <param name="b2">The second byte of the encoded tag</param>
|
||||
/// <param name="b3">The third byte of the encoded tag</param>
|
||||
public void WriteRawTag(byte b1, byte b2, byte b3)
|
||||
{
|
||||
WriteRawByte(b1);
|
||||
@ -353,6 +413,10 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes the given four-byte tag directly to the stream.
|
||||
/// </summary>
|
||||
/// <param name="b1">The first byte of the encoded tag</param>
|
||||
/// <param name="b2">The second byte of the encoded tag</param>
|
||||
/// <param name="b3">The third byte of the encoded tag</param>
|
||||
/// <param name="b4">The fourth byte of the encoded tag</param>
|
||||
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
|
||||
{
|
||||
WriteRawByte(b1);
|
||||
@ -364,6 +428,11 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes the given five-byte tag directly to the stream.
|
||||
/// </summary>
|
||||
/// <param name="b1">The first byte of the encoded tag</param>
|
||||
/// <param name="b2">The second byte of the encoded tag</param>
|
||||
/// <param name="b3">The third byte of the encoded tag</param>
|
||||
/// <param name="b4">The fourth byte of the encoded tag</param>
|
||||
/// <param name="b5">The fifth byte of the encoded tag</param>
|
||||
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
|
||||
{
|
||||
WriteRawByte(b1);
|
||||
@ -380,7 +449,7 @@ namespace Google.Protobuf
|
||||
/// there's enough buffer space left to whizz through without checking
|
||||
/// for each byte; otherwise, we resort to calling WriteRawByte each time.
|
||||
/// </summary>
|
||||
public void WriteRawVarint32(uint value)
|
||||
internal void WriteRawVarint32(uint value)
|
||||
{
|
||||
// Optimize for the common case of a single byte value
|
||||
if (value < 128 && position < limit)
|
||||
@ -409,7 +478,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteRawVarint64(ulong value)
|
||||
internal void WriteRawVarint64(ulong value)
|
||||
{
|
||||
while (value > 127 && position < limit)
|
||||
{
|
||||
@ -431,7 +500,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteRawLittleEndian32(uint value)
|
||||
internal void WriteRawLittleEndian32(uint value)
|
||||
{
|
||||
if (position + 4 > limit)
|
||||
{
|
||||
@ -449,7 +518,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteRawLittleEndian64(ulong value)
|
||||
internal void WriteRawLittleEndian64(ulong value)
|
||||
{
|
||||
if (position + 8 > limit)
|
||||
{
|
||||
@ -475,7 +544,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteRawByte(byte value)
|
||||
internal void WriteRawByte(byte value)
|
||||
{
|
||||
if (position == limit)
|
||||
{
|
||||
@ -485,7 +554,7 @@ namespace Google.Protobuf
|
||||
buffer[position++] = value;
|
||||
}
|
||||
|
||||
public void WriteRawByte(uint value)
|
||||
internal void WriteRawByte(uint value)
|
||||
{
|
||||
WriteRawByte((byte) value);
|
||||
}
|
||||
@ -493,7 +562,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes out an array of bytes.
|
||||
/// </summary>
|
||||
public void WriteRawBytes(byte[] value)
|
||||
internal void WriteRawBytes(byte[] value)
|
||||
{
|
||||
WriteRawBytes(value, 0, value.Length);
|
||||
}
|
||||
@ -501,7 +570,7 @@ namespace Google.Protobuf
|
||||
/// <summary>
|
||||
/// Writes out part of an array of bytes.
|
||||
/// </summary>
|
||||
public void WriteRawBytes(byte[] value, int offset, int length)
|
||||
internal void WriteRawBytes(byte[] value, int offset, int length)
|
||||
{
|
||||
if (limit - position >= length)
|
||||
{
|
||||
@ -548,7 +617,7 @@ namespace Google.Protobuf
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
public static uint EncodeZigZag32(int n)
|
||||
internal static uint EncodeZigZag32(int n)
|
||||
{
|
||||
// Note: the right-shift must be arithmetic
|
||||
return (uint) ((n << 1) ^ (n >> 31));
|
||||
@ -563,7 +632,7 @@ namespace Google.Protobuf
|
||||
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||
/// 10 bytes on the wire.)
|
||||
/// </remarks>
|
||||
public static ulong EncodeZigZag64(long n)
|
||||
internal static ulong EncodeZigZag64(long n)
|
||||
{
|
||||
return (ulong) ((n << 1) ^ (n >> 63));
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace Google.Protobuf.Collections
|
||||
/// <summary>
|
||||
/// Read-only wrapper around another dictionary.
|
||||
/// </summary>
|
||||
public sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
||||
internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
||||
{
|
||||
private readonly IDictionary<TKey, TValue> wrapped;
|
||||
|
||||
|
@ -51,12 +51,14 @@ namespace Google.Protobuf.Collections
|
||||
|
||||
public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
|
||||
{
|
||||
// TODO: Inline some of the Add code, so we can avoid checking the size on every
|
||||
// iteration and the mutability.
|
||||
uint tag = input.LastTag;
|
||||
var reader = codec.ValueReader;
|
||||
// Value types can be packed or not.
|
||||
if (typeof(T).IsValueType && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited)
|
||||
{
|
||||
int length = (int)(input.ReadRawVarint32() & int.MaxValue);
|
||||
int length = input.ReadLength();
|
||||
if (length > 0)
|
||||
{
|
||||
int oldLimit = input.PushLimit(length);
|
||||
@ -125,7 +127,6 @@ namespace Google.Protobuf.Collections
|
||||
|
||||
public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
|
||||
{
|
||||
// TODO: Assert that T is a value type, and that codec.Tag is packed?
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
@ -172,9 +173,9 @@ namespace Google.Protobuf.Collections
|
||||
|
||||
private void EnsureSize(int size)
|
||||
{
|
||||
size = Math.Max(size, MinArraySize);
|
||||
if (array.Length < size)
|
||||
{
|
||||
size = Math.Max(size, MinArraySize);
|
||||
int newSize = Math.Max(array.Length * 2, size);
|
||||
var tmp = new T[newSize];
|
||||
Array.Copy(array, 0, tmp, 0, array.Length);
|
||||
|
@ -8,6 +8,7 @@ namespace Google.Protobuf
|
||||
/// </summary>
|
||||
public static class FieldCodec
|
||||
{
|
||||
// TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
|
||||
public static FieldCodec<string> ForString(uint tag)
|
||||
{
|
||||
return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
|
||||
@ -84,7 +85,7 @@ namespace Google.Protobuf
|
||||
}
|
||||
|
||||
// Enums are tricky. We can probably use expression trees to build these delegates automatically,
|
||||
// but it's easy to generate the code fdor it.
|
||||
// but it's easy to generate the code for it.
|
||||
public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
|
||||
{
|
||||
return new FieldCodec<T>(input => fromInt32(
|
||||
|
@ -38,7 +38,7 @@ namespace Google.Protobuf
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(message, "message");
|
||||
ThrowHelper.ThrowIfNull(input, "input");
|
||||
int size = (int)CodedInputStream.ReadRawVarint32(input);
|
||||
int size = (int) CodedInputStream.ReadRawVarint32(input);
|
||||
Stream limitedStream = new LimitedInputStream(input, size);
|
||||
message.MergeFrom(limitedStream);
|
||||
}
|
||||
|
@ -61,6 +61,13 @@ using System.Security;
|
||||
|
||||
[assembly: AssemblyVersion("2.4.1.555")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" +
|
||||
"00240000048000009400000006020000002400005253413100040000110000003b4611704c5379" +
|
||||
"39c3e0fbe9447dd6fa5462507f9dd4fd9fbf0712457e415b037da6d2c4eb5d2c7d29c86380af68" +
|
||||
"7cf400401bb183f2a70bd3b631c1fcb7db8aa66c766694a9fb53fa765df6303104da8c978f3b6d" +
|
||||
"53909cd30685b8bc9922c726cd82b5995e9e2cfca6df7a2d189d851492e49f4b76f269ce6dfd08" +
|
||||
"c34a7d98")]
|
||||
|
||||
#if !NOFILEVERSION
|
||||
[assembly: AssemblyFileVersion("2.4.1.555")]
|
||||
#endif
|
||||
|
@ -53,13 +53,13 @@ namespace Google.Protobuf
|
||||
#region Fixed sizes.
|
||||
|
||||
// TODO(jonskeet): Move these somewhere else. They're messy. Consider making FieldType a smarter kind of enum
|
||||
public const int Fixed32Size = 4;
|
||||
public const int Fixed64Size = 8;
|
||||
public const int SFixed32Size = 4;
|
||||
public const int SFixed64Size = 8;
|
||||
public const int FloatSize = 4;
|
||||
public const int DoubleSize = 8;
|
||||
public const int BoolSize = 1;
|
||||
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
|
||||
|
||||
@ -72,22 +72,7 @@ namespace Google.Protobuf
|
||||
EndGroup = 4,
|
||||
Fixed32 = 5
|
||||
}
|
||||
|
||||
internal static class MessageSetField
|
||||
{
|
||||
internal const int Item = 1;
|
||||
internal const int TypeID = 2;
|
||||
internal const int Message = 3;
|
||||
}
|
||||
|
||||
internal static class MessageSetTag
|
||||
{
|
||||
internal static readonly uint ItemStart = MakeTag(MessageSetField.Item, WireType.StartGroup);
|
||||
internal static readonly uint ItemEnd = MakeTag(MessageSetField.Item, WireType.EndGroup);
|
||||
internal static readonly uint TypeID = MakeTag(MessageSetField.TypeID, WireType.Varint);
|
||||
internal static readonly uint Message = MakeTag(MessageSetField.Message, WireType.LengthDelimited);
|
||||
}
|
||||
|
||||
|
||||
private const int TagTypeBits = 3;
|
||||
private const uint TagTypeMask = (1 << TagTypeBits) - 1;
|
||||
|
||||
@ -120,7 +105,6 @@ namespace Google.Protobuf
|
||||
return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
|
||||
}
|
||||
|
||||
#if !LITE
|
||||
public static uint MakeTag(FieldDescriptor field)
|
||||
{
|
||||
return MakeTag(field.FieldNumber, GetWireType(field));
|
||||
@ -135,8 +119,6 @@ namespace Google.Protobuf
|
||||
return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <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.
|
||||
@ -177,7 +159,7 @@ namespace Google.Protobuf
|
||||
case FieldType.Enum:
|
||||
return WireType.Varint;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("No such field type");
|
||||
throw new ArgumentOutOfRangeException("fieldType", "No such field type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user