diff options
40 files changed, 374 insertions, 1052 deletions
diff --git a/Makefile.am b/Makefile.am index bb735177..3eb46d7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -468,7 +468,6 @@ objectivec_EXTRA_DIST= \ objectivec/Tests/GPBMessageTests.m \ objectivec/Tests/GPBObjectiveCPlusPlusTest.mm \ objectivec/Tests/GPBPerfTests.m \ - objectivec/Tests/GPBStringTests.m \ objectivec/Tests/GPBSwiftTests.swift \ objectivec/Tests/GPBTestUtilities.h \ objectivec/Tests/GPBTestUtilities.m \ diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs index d5455d80..2c81004c 100644 --- a/csharp/src/AddressBook/Addressbook.cs +++ b/csharp/src/AddressBook/Addressbook.cs @@ -43,6 +43,9 @@ namespace Google.Protobuf.Examples.AddressBook { } #region Messages + /// <summary> + /// [START messages] + /// </summary> [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Person : pb::IMessage<Person> { private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person()); @@ -143,7 +146,7 @@ namespace Google.Protobuf.Examples.AddressBook { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -302,7 +305,7 @@ namespace Google.Protobuf.Examples.AddressBook { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -426,7 +429,7 @@ namespace Google.Protobuf.Examples.AddressBook { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs index 50ce1de4..f135d768 100644 --- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs +++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs @@ -284,7 +284,7 @@ namespace Conformance { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -532,7 +532,7 @@ namespace Conformance { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1544,7 +1544,7 @@ namespace Conformance { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2343,7 +2343,7 @@ namespace Conformance { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2471,7 +2471,7 @@ namespace Conformance { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Conformance/Program.cs b/csharp/src/Google.Protobuf.Conformance/Program.cs index af92da9f..8f72c8f9 100644 --- a/csharp/src/Google.Protobuf.Conformance/Program.cs +++ b/csharp/src/Google.Protobuf.Conformance/Program.cs @@ -31,6 +31,7 @@ #endregion using Conformance; +using Google.Protobuf.Reflection; using System; using System.IO; @@ -47,16 +48,17 @@ namespace Google.Protobuf.Conformance // This way we get the binary streams instead of readers/writers. var input = new BinaryReader(Console.OpenStandardInput()); var output = new BinaryWriter(Console.OpenStandardOutput()); + var typeRegistry = TypeRegistry.FromMessages(TestAllTypes.Descriptor); int count = 0; - while (RunTest(input, output)) + while (RunTest(input, output, typeRegistry)) { count++; } Console.Error.WriteLine("Received EOF after {0} tests", count); } - private static bool RunTest(BinaryReader input, BinaryWriter output) + private static bool RunTest(BinaryReader input, BinaryWriter output, TypeRegistry typeRegistry) { int? size = ReadInt32(input); if (size == null) @@ -69,7 +71,7 @@ namespace Google.Protobuf.Conformance throw new EndOfStreamException("Read " + inputData.Length + " bytes of data when expecting " + size); } ConformanceRequest request = ConformanceRequest.Parser.ParseFrom(inputData); - ConformanceResponse response = PerformRequest(request); + ConformanceResponse response = PerformRequest(request, typeRegistry); byte[] outputData = response.ToByteArray(); output.Write(outputData.Length); output.Write(outputData); @@ -77,30 +79,33 @@ namespace Google.Protobuf.Conformance return true; } - private static ConformanceResponse PerformRequest(ConformanceRequest request) + private static ConformanceResponse PerformRequest(ConformanceRequest request, TypeRegistry typeRegistry) { TestAllTypes message; - switch (request.PayloadCase) + try { - case ConformanceRequest.PayloadOneofCase.JsonPayload: - return new ConformanceResponse { Skipped = "JSON parsing not implemented in C# yet" }; - case ConformanceRequest.PayloadOneofCase.ProtobufPayload: - try - { + switch (request.PayloadCase) + { + case ConformanceRequest.PayloadOneofCase.JsonPayload: + var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry)); + message = parser.Parse<TestAllTypes>(request.JsonPayload); + break; + case ConformanceRequest.PayloadOneofCase.ProtobufPayload: message = TestAllTypes.Parser.ParseFrom(request.ProtobufPayload); - } - catch (InvalidProtocolBufferException e) - { - return new ConformanceResponse { ParseError = e.Message }; - } - break; - default: - throw new Exception("Unsupported request payload: " + request.PayloadCase); + break; + default: + throw new Exception("Unsupported request payload: " + request.PayloadCase); + } + } + catch (InvalidProtocolBufferException e) + { + return new ConformanceResponse { ParseError = e.Message }; } switch (request.RequestedOutputFormat) { case global::Conformance.WireFormat.JSON: - return new ConformanceResponse { JsonPayload = JsonFormatter.Default.Format(message) }; + var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry)); + return new ConformanceResponse { JsonPayload = formatter.Format(message) }; case global::Conformance.WireFormat.PROTOBUF: return new ConformanceResponse { ProtobufPayload = message.ToByteString() }; default: diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs index 5ff47ed2..3e9999e4 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs @@ -425,7 +425,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -633,7 +633,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -741,7 +741,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -851,7 +851,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1121,7 +1121,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1318,7 +1318,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1427,7 +1427,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs index f257b46c..72ada3de 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs @@ -110,7 +110,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs index 2881ca0f..45f0e247 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportPublicProto3.cs @@ -96,7 +96,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs index cf34e8bc..9ac2d7ac 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs @@ -126,7 +126,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -204,7 +204,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -282,7 +282,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -405,7 +405,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -511,7 +511,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -668,7 +668,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -831,7 +831,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -947,7 +947,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1056,7 +1056,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1279,7 +1279,7 @@ namespace UnitTest.Issues.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs index 04de603b..462ae9f9 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs @@ -927,7 +927,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1600,7 +1600,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1736,7 +1736,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1873,7 +1873,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1980,7 +1980,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2070,7 +2070,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2162,7 +2162,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2291,7 +2291,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2421,7 +2421,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2547,7 +2547,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2669,7 +2669,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2883,7 +2883,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3107,7 +3107,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3278,7 +3278,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3400,7 +3400,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3506,7 +3506,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3608,7 +3608,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3704,7 +3704,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3807,7 +3807,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3913,7 +3913,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4016,7 +4016,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4119,7 +4119,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4222,7 +4222,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4325,7 +4325,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4486,7 +4486,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4780,7 +4780,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5140,7 +5140,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5414,7 +5414,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5554,7 +5554,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5647,7 +5647,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5723,7 +5723,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5799,7 +5799,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5875,7 +5875,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5951,7 +5951,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -6027,7 +6027,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs index 642e5f91..c00b0f41 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestWellKnownTypes.cs @@ -466,7 +466,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1106,7 +1106,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1625,7 +1625,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2213,7 +2213,7 @@ namespace Google.Protobuf.TestProtos { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs index 0a2b8b32..f3593e5f 100644 --- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs +++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs @@ -62,5 +62,28 @@ namespace Google.Protobuf.WellKnownTypes var unpacked = any.Unpack<TestAllTypes>(); Assert.AreEqual(message, unpacked); } + + [Test] + public void ToString_WithValues() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var any = Any.Pack(message); + var text = any.ToString(); + Assert.That(text, Is.StringContaining("\"@value\": \"" + message.ToByteString().ToBase64() + "\"")); + } + + [Test] + public void ToString_Empty() + { + var any = new Any(); + Assert.AreEqual("{ \"@type\": \"\", \"@value\": \"\" }", any.ToString()); + } + + [Test] + public void ToString_MessageContainingAny() + { + var message = new TestWellKnownTypes { AnyField = new Any() }; + Assert.AreEqual("{ \"anyField\": { \"@type\": \"\", \"@value\": \"\" } }", message.ToString()); + } } } diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index 36807b82..e6af2483 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -16,6 +16,8 @@ <FileAlignment>512</FileAlignment>
<OldToolsVersion>3.5</OldToolsVersion>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -142,9 +144,17 @@ </ItemGroup>
<ItemGroup>
<None Include="Google.Protobuf.nuspec" />
+ <None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
+ <Import Project="..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets" Condition="Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NuSpec.ReferenceGenerator.1.4.1\build\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\NuSpec.ReferenceGenerator.targets'))" />
+ </Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec index 9542138a..2f691e3c 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec +++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec @@ -1,11 +1,11 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <package> <metadata> <id>Google.Protobuf</id> <title>Google Protocol Buffers C#</title> <summary>C# runtime library for Protocol Buffers - Google's data interchange format.</summary> <description>See project site for more info.</description> - <version>3.0.0-alpha4</version> + <version>3.0.0-beta2</version> <authors>Google Inc.</authors> <owners>protobuf-packages</owners> <licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl> @@ -14,24 +14,43 @@ <releaseNotes>C# proto3 support</releaseNotes> <copyright>Copyright 2015, Google Inc.</copyright> <tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags> + <dependencies> + <group targetFramework="dotnet"> + <dependency id="System.Collections" version="4.0.0" /> + <dependency id="System.Diagnostics.Debug" version="4.0.0" /> + <dependency id="System.Globalization" version="4.0.0" /> + <dependency id="System.IO" version="4.0.0" /> + <dependency id="System.Linq" version="4.0.0" /> + <dependency id="System.Linq.Expressions" version="4.0.0" /> + <dependency id="System.ObjectModel" version="4.0.0" /> + <dependency id="System.Reflection" version="4.0.0" /> + <dependency id="System.Runtime" version="4.0.0" /> + <dependency id="System.Runtime.Extensions" version="4.0.0" /> + <dependency id="System.Text.Encoding" version="4.0.0" /> + <dependency id="System.Text.RegularExpressions" version="4.0.0" /> + </group> + </dependencies> </metadata> <files> <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/portable-net45+netcore45+wpa81+wp8" /> - <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" /> - <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" /> - <file src="**\*.cs" target="src" /> - <file src="..\..\..\cmake\Release\protoc.exe" target="tools" /> - <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" /> - <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" /> + <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/portable-net45+netcore45+wpa81+wp8" /> + <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/portable-net45+netcore45+wpa81+wp8" /> + <file src="bin/ReleaseSigned/Google.Protobuf.dll" target="lib/dotnet" /> + <file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" /> + <file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" /> + <file src="**\*.cs" target="src" /> + <file src="..\..\..\cmake\Release\protoc.exe" target="tools" /> + <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" /> + <file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" /> </files> -</package> +</package>
\ No newline at end of file diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 45941b39..7b99f314 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -56,17 +56,19 @@ namespace Google.Protobuf public sealed class JsonFormatter { internal const string AnyTypeUrlField = "@type"; + internal const string AnyDiagnosticValueField = "@value"; internal const string AnyWellKnownTypeValueField = "value"; private const string TypeUrlPrefix = "type.googleapis.com"; private const string NameValueSeparator = ": "; private const string PropertySeparator = ", "; - private static JsonFormatter defaultInstance = new JsonFormatter(Settings.Default); - /// <summary> /// Returns a formatter using the default settings. /// </summary> - public static JsonFormatter Default { get { return defaultInstance; } } + public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default); + + // A JSON formatter which *only* exists + private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default); /// <summary> /// The JSON representation of the first 160 characters of Unicode. @@ -149,6 +151,29 @@ namespace Google.Protobuf return builder.ToString(); } + /// <summary> + /// Converts a message to JSON for diagnostic purposes with no extra context. + /// </summary> + /// <remarks> + /// <para> + /// This differs from calling <see cref="Format(IMessage)"/> on the default JSON + /// formatter in its handling of <see cref="Any"/>. As no type registry is available + /// in <see cref="object.ToString"/> calls, the normal way of resolving the type of + /// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c> + /// is included with the base64 data from the <see cref="Any.Value"/> property of the message. + /// </para> + /// <para>The value returned by this method is only designed to be used for diagnostic + /// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable + /// by other Protocol Buffer implementations.</para> + /// </remarks> + /// <param name="message">The message to format for diagnostic purposes.</param> + /// <returns>The diagnostic-only JSON representation of the message</returns> + public static string ToDiagnosticString(IMessage message) + { + Preconditions.CheckNotNull(message, nameof(message)); + return diagnosticFormatter.Format(message); + } + private void WriteMessage(StringBuilder builder, IMessage message) { if (message == null) @@ -516,6 +541,12 @@ namespace Google.Protobuf private void WriteAny(StringBuilder builder, IMessage value) { + if (ReferenceEquals(this, diagnosticFormatter)) + { + WriteDiagnosticOnlyAny(builder, value); + return; + } + string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value); ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value); string typeName = GetTypeName(typeUrl); @@ -544,6 +575,23 @@ namespace Google.Protobuf builder.Append(" }"); } + private void WriteDiagnosticOnlyAny(StringBuilder builder, IMessage value) + { + string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value); + ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value); + builder.Append("{ "); + WriteString(builder, AnyTypeUrlField); + builder.Append(NameValueSeparator); + WriteString(builder, typeUrl); + builder.Append(PropertySeparator); + WriteString(builder, AnyDiagnosticValueField); + builder.Append(NameValueSeparator); + builder.Append('"'); + builder.Append(data.ToBase64()); + builder.Append('"'); + builder.Append(" }"); + } + internal static string GetTypeName(String typeUrl) { string[] parts = typeUrl.Split('/'); diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs index 03685322..d29424ad 100644 --- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs @@ -225,7 +225,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -489,7 +489,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -827,7 +827,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1021,7 +1021,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1162,7 +1162,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1436,7 +1436,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1741,7 +1741,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1872,7 +1872,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2031,7 +2031,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2196,7 +2196,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2404,7 +2404,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -2863,7 +2863,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3302,7 +3302,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3596,7 +3596,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3845,7 +3845,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -3990,7 +3990,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4121,7 +4121,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4252,7 +4252,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4451,7 +4451,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4653,7 +4653,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -4823,7 +4823,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -5051,7 +5051,7 @@ namespace Google.Protobuf.Reflection { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs index 0b830b66..efa60a68 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs @@ -165,7 +165,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs index e9330e69..1b925b9c 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs @@ -230,7 +230,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -503,7 +503,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -783,7 +783,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs index 42fda452..4eeff4f0 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs @@ -164,7 +164,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs index 92bc0397..d568a811 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs @@ -94,7 +94,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs index 963b72be..0cd5952a 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs @@ -221,7 +221,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs index d5385642..2972b346 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs @@ -105,7 +105,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs index 73e3cae2..a811ea8b 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs @@ -136,7 +136,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -361,7 +361,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -555,7 +555,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs index 499b0950..adee4bb4 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs @@ -175,7 +175,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs index ef368bd3..a76d02b4 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs @@ -230,7 +230,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -522,7 +522,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -910,7 +910,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1098,7 +1098,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1244,7 +1244,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs index a70b2fb0..43148772 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs @@ -117,7 +117,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -228,7 +228,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -339,7 +339,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -450,7 +450,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -561,7 +561,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -672,7 +672,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -783,7 +783,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -894,7 +894,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { @@ -1005,7 +1005,7 @@ namespace Google.Protobuf.WellKnownTypes { } public override string ToString() { - return pb::JsonFormatter.Default.Format(this); + return pb::JsonFormatter.ToDiagnosticString(this); } public void WriteTo(pb::CodedOutputStream output) { diff --git a/csharp/src/Google.Protobuf/packages.config b/csharp/src/Google.Protobuf/packages.config new file mode 100644 index 00000000..40b8fd92 --- /dev/null +++ b/csharp/src/Google.Protobuf/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NuSpec.ReferenceGenerator" version="1.4.1" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" /> +</packages>
\ No newline at end of file diff --git a/examples/add_person.go b/examples/add_person.go index 6b2d3d69..4f2e7f74 100644 --- a/examples/add_person.go +++ b/examples/add_person.go @@ -105,7 +105,10 @@ func main() { log.Fatalln("Error reading file:", err) } } + + // [START marshal_proto] book := &pb.AddressBook{} + // [START_EXCLUDE] if err := proto.Unmarshal(in, book); err != nil { log.Fatalln("Failed to parse address book:", err) } @@ -116,6 +119,7 @@ func main() { log.Fatalln("Error with address:", err) } book.People = append(book.People, addr) + // [END_EXCLUDE] // Write the new address book back to disk. out, err := proto.Marshal(book) @@ -125,4 +129,5 @@ func main() { if err := ioutil.WriteFile(fname, out, 0644); err != nil { log.Fatalln("Failed to write address book:", err) } + // [END marshal_proto] } diff --git a/examples/list_people.go b/examples/list_people.go index 48b1fbfa..70bc589e 100644 --- a/examples/list_people.go +++ b/examples/list_people.go @@ -11,25 +11,29 @@ import ( pb "github.com/google/protobuf/examples/tutorial" ) -func listPeople(w io.Writer, book *pb.AddressBook) { - for _, p := range book.People { - fmt.Fprintln(w, "Person ID:", p.Id) - fmt.Fprintln(w, " Name:", p.Name) - if p.Email != "" { - fmt.Fprintln(w, " E-mail address:", p.Email) - } +func writePerson(w io.Writer, p *pb.Person) { + fmt.Fprintln(w, "Person ID:", p.Id) + fmt.Fprintln(w, " Name:", p.Name) + if p.Email != "" { + fmt.Fprintln(w, " E-mail address:", p.Email) + } - for _, pn := range p.Phones { - switch pn.Type { - case pb.Person_MOBILE: - fmt.Fprint(w, " Mobile phone #: ") - case pb.Person_HOME: - fmt.Fprint(w, " Home phone #: ") - case pb.Person_WORK: - fmt.Fprint(w, " Work phone #: ") - } - fmt.Fprintln(w, pn.Number) + for _, pn := range p.Phones { + switch pn.Type { + case pb.Person_MOBILE: + fmt.Fprint(w, " Mobile phone #: ") + case pb.Person_HOME: + fmt.Fprint(w, " Home phone #: ") + case pb.Person_WORK: + fmt.Fprint(w, " Work phone #: ") } + fmt.Fprintln(w, pn.Number) + } +} + +func listPeople(w io.Writer, book *pb.AddressBook) { + for _, p := range book.People { + writePerson(w, p) } } @@ -41,19 +45,17 @@ func main() { } fname := os.Args[1] + // [START unmarshal_proto] // Read the existing address book. in, err := ioutil.ReadFile(fname) if err != nil { - if os.IsNotExist(err) { - fmt.Printf("%s: File not found. Creating new file.\n", fname) - } else { - log.Fatalln("Error reading file:", err) - } + log.Fatalln("Error reading file:", err) } book := &pb.AddressBook{} if err := proto.Unmarshal(in, book); err != nil { log.Fatalln("Failed to parse address book:", err) } + // [END unmarshal_proto] listPeople(os.Stdout, book) } diff --git a/examples/list_people_test.go b/examples/list_people_test.go index 721d3555..87d6ad6e 100644 --- a/examples/list_people_test.go +++ b/examples/list_people_test.go @@ -8,6 +8,30 @@ import ( pb "github.com/google/protobuf/examples/tutorial" ) +func TestWritePersonWritesPerson(t *testing.T) { + buf := new(bytes.Buffer) + // [START populate_proto] + p := pb.Person{ + Id: 1234, + Name: "John Doe", + Email: "jdoe@example.com", + Phones: []*pb.Person_PhoneNumber{ + {Number: "555-4321", Type: pb.Person_HOME}, + }, + } + // [END populate_proto] + writePerson(buf, &p) + got := buf.String() + want := `Person ID: 1234 + Name: John Doe + E-mail address: jdoe@example.com + Home phone #: 555-4321 +` + if got != want { + t.Errorf("writePerson(%s) =>\n\t%q, want %q", p.String(), got, want) + } +} + func TestListPeopleWritesList(t *testing.T) { buf := new(bytes.Buffer) in := pb.AddressBook{[]*pb.Person{ diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m index 9371228a..fd877838 100644 --- a/objectivec/GPBCodedInputStream.m +++ b/objectivec/GPBCodedInputStream.m @@ -216,7 +216,17 @@ NSString *GPBCodedInputStreamReadRetainedString( result = @""; } else { CheckSize(state, size); - result = GPBCreateGPBStringWithUTF8(&state->bytes[state->bufferPos], size); + result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos] + length:size + encoding:NSUTF8StringEncoding]; + if (!result) { + result = @""; +#ifdef DEBUG + // https://developers.google.com/protocol-buffers/docs/proto#scalar + NSLog(@"UTF8 failure, is some field type 'string' when it should be " + @"'bytes'?"); +#endif + } state->bufferPos += size; } return result; @@ -478,320 +488,3 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, } @end - -@implementation GPBString { - @package - CFStringRef string_; - unsigned char *utf8_; - NSUInteger utf8Len_; - - // This lock is used to gate access to utf8_. Once GPBStringInitStringValue() - // has been called, string_ will be filled in, and utf8_ will be NULL. - OSSpinLock lock_; - - BOOL hasBOM_; - BOOL is7BitAscii_; -} - -// Returns true if the passed in bytes are 7 bit ascii. -// This routine needs to be fast. -static bool AreBytesIn7BitASCII(const uint8_t *bytes, NSUInteger len) { -// In the loops below, it's more efficient to collect rather than do -// conditional at every step. -#if __LP64__ - // Align bytes. This is especially important in case of 3 byte BOM. - while (len > 0 && ((size_t)bytes & 0x07)) { - if (*bytes++ & 0x80) return false; - len--; - } - while (len >= 32) { - uint64_t val = *(const uint64_t *)bytes; - uint64_t hiBits = (val & 0x8080808080808080ULL); - bytes += 8; - val = *(const uint64_t *)bytes; - hiBits |= (val & 0x8080808080808080ULL); - bytes += 8; - val = *(const uint64_t *)bytes; - hiBits |= (val & 0x8080808080808080ULL); - bytes += 8; - val = *(const uint64_t *)bytes; - if (hiBits | (val & 0x8080808080808080ULL)) return false; - bytes += 8; - len -= 32; - } - - while (len >= 16) { - uint64_t val = *(const uint64_t *)bytes; - uint64_t hiBits = (val & 0x8080808080808080ULL); - bytes += 8; - val = *(const uint64_t *)bytes; - if (hiBits | (val & 0x8080808080808080ULL)) return false; - bytes += 8; - len -= 16; - } - - while (len >= 8) { - uint64_t val = *(const uint64_t *)bytes; - if (val & 0x8080808080808080ULL) return false; - bytes += 8; - len -= 8; - } -#else // __LP64__ - // Align bytes. This is especially important in case of 3 byte BOM. - while (len > 0 && ((size_t)bytes & 0x03)) { - if (*bytes++ & 0x80) return false; - len--; - } - while (len >= 16) { - uint32_t val = *(const uint32_t *)bytes; - uint32_t hiBits = (val & 0x80808080U); - bytes += 4; - val = *(const uint32_t *)bytes; - hiBits |= (val & 0x80808080U); - bytes += 4; - val = *(const uint32_t *)bytes; - hiBits |= (val & 0x80808080U); - bytes += 4; - val = *(const uint32_t *)bytes; - if (hiBits | (val & 0x80808080U)) return false; - bytes += 4; - len -= 16; - } - - while (len >= 8) { - uint32_t val = *(const uint32_t *)bytes; - uint32_t hiBits = (val & 0x80808080U); - bytes += 4; - val = *(const uint32_t *)bytes; - if (hiBits | (val & 0x80808080U)) return false; - bytes += 4; - len -= 8; - } -#endif // __LP64__ - - while (len >= 4) { - uint32_t val = *(const uint32_t *)bytes; - if (val & 0x80808080U) return false; - bytes += 4; - len -= 4; - } - - while (len--) { - if (*bytes++ & 0x80) return false; - } - - return true; -} - -static void GPBStringInitStringValue(GPBString *string) { - OSSpinLockLock(&string->lock_); - GPBStringInitStringValueAlreadyLocked(string); - OSSpinLockUnlock(&string->lock_); -} - -static void GPBStringInitStringValueAlreadyLocked(GPBString *string) { - if (string->string_ == NULL && string->utf8_ != NULL) { - // Using kCFAllocatorMalloc for contentsDeallocator, as buffer in - // string->utf8_ is being handed off. - string->string_ = CFStringCreateWithBytesNoCopy( - NULL, string->utf8_, string->utf8Len_, kCFStringEncodingUTF8, false, - kCFAllocatorMalloc); - if (!string->string_) { -#ifdef DEBUG - // https://developers.google.com/protocol-buffers/docs/proto#scalar - NSLog(@"UTF8 failure, is some field type 'string' when it should be " - @"'bytes'?"); -#endif - string->string_ = CFSTR(""); - string->utf8Len_ = 0; - // On failure, we have to clean up the buffer. - free(string->utf8_); - } - string->utf8_ = NULL; - } -} - -GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) { - GPBString *result = [[GPBString alloc] initWithBytes:bytes length:length]; - return result; -} - -- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)length { - self = [super init]; - if (self) { - utf8_ = malloc(length); - memcpy(utf8_, bytes, length); - utf8Len_ = length; - lock_ = OS_SPINLOCK_INIT; - is7BitAscii_ = AreBytesIn7BitASCII(bytes, length); - if (length >= 3 && memcmp(utf8_, "\xef\xbb\xbf", 3) == 0) { - // We can't just remove the BOM from the string here, because in the case - // where we have > 1 BOM at the beginning of the string, we will remove one, - // and the internal NSString we create will remove the next one, and we will - // end up with a GPBString != NSString issue. - // We also just can't remove all the BOMs because then we would end up with - // potential cases where a GPBString and an NSString made with the same - // UTF8 buffer would in fact be different. - // We record the fact we have a BOM, and use it as necessary to simulate - // what NSString would return for various calls. - hasBOM_ = YES; -#if DEBUG - // Sending BOMs across the line is just wasting bits. - NSLog(@"Bad data? String should not have BOM!"); -#endif // DEBUG - } - } - return self; -} - -- (void)dealloc { - if (string_ != NULL) { - CFRelease(string_); - } - if (utf8_ != NULL) { - free(utf8_); - } - [super dealloc]; -} - -// Required NSString overrides. -- (NSUInteger)length { - if (is7BitAscii_) { - return utf8Len_; - } else { - GPBStringInitStringValue(self); - return CFStringGetLength(string_); - } -} - -- (unichar)characterAtIndex:(NSUInteger)anIndex { - OSSpinLockLock(&lock_); - if (is7BitAscii_ && utf8_) { - unichar result = utf8_[anIndex]; - OSSpinLockUnlock(&lock_); - return result; - } else { - GPBStringInitStringValueAlreadyLocked(self); - OSSpinLockUnlock(&lock_); - return CFStringGetCharacterAtIndex(string_, anIndex); - } -} - -// Override a couple of methods that typically want high performance. - -- (id)copyWithZone:(NSZone *)zone { - GPBStringInitStringValue(self); - return [(NSString *)string_ copyWithZone:zone]; -} - -- (id)mutableCopyWithZone:(NSZone *)zone { - GPBStringInitStringValue(self); - return [(NSString *)string_ mutableCopyWithZone:zone]; -} - -- (NSUInteger)hash { - // Must convert to string here to make sure that the hash is always - // consistent no matter what state the GPBString is in. - GPBStringInitStringValue(self); - return CFHash(string_); -} - -- (BOOL)isEqual:(id)object { - if (self == object) { - return YES; - } - if ([object isKindOfClass:[NSString class]]) { - GPBStringInitStringValue(self); - return CFStringCompare(string_, (CFStringRef)object, 0) == - kCFCompareEqualTo; - } - return NO; -} - -- (void)getCharacters:(unichar *)buffer range:(NSRange)aRange { - OSSpinLockLock(&lock_); - if (is7BitAscii_ && utf8_) { - unsigned char *bytes = &(utf8_[aRange.location]); - for (NSUInteger i = 0; i < aRange.length; ++i) { - buffer[i] = bytes[i]; - } - OSSpinLockUnlock(&lock_); - } else { - GPBStringInitStringValueAlreadyLocked(self); - OSSpinLockUnlock(&lock_); - CFStringGetCharacters(string_, CFRangeMake(aRange.location, aRange.length), - buffer); - } -} - -- (NSUInteger)lengthOfBytesUsingEncoding:(NSStringEncoding)encoding { - if ((encoding == NSUTF8StringEncoding) || - (encoding == NSASCIIStringEncoding && is7BitAscii_)) { - return utf8Len_ - (hasBOM_ ? 3 : 0); - } else { - GPBStringInitStringValue(self); - return [(NSString *)string_ lengthOfBytesUsingEncoding:encoding]; - } -} - -- (BOOL)getBytes:(void *)buffer - maxLength:(NSUInteger)maxLength - usedLength:(NSUInteger *)usedLength - encoding:(NSStringEncoding)encoding - options:(NSStringEncodingConversionOptions)options - range:(NSRange)range - remainingRange:(NSRangePointer)remainingRange { - // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] - // does not return reliable results if the maxLength argument is 0 - // (Radar 16385183). Therefore we have special cased it as a slow case so - // that it behaves however Apple intends it to behave. It should be a rare - // case. - // - // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] - // does not return reliable results if the range is outside of the strings - // length (Radar 16396177). Therefore we have special cased it as a slow - // case so that it behaves however Apple intends it to behave. It should - // be a rare case. - // - // We can optimize the UTF8StringEncoding and NSASCIIStringEncoding with no - // options cases. - if ((options == 0) && - (encoding == NSUTF8StringEncoding || encoding == NSASCIIStringEncoding) && - (maxLength != 0) && - (NSMaxRange(range) <= utf8Len_)) { - // Might be able to optimize it. - OSSpinLockLock(&lock_); - if (is7BitAscii_ && utf8_) { - NSUInteger length = range.length; - length = (length < maxLength) ? length : maxLength; - memcpy(buffer, utf8_ + range.location, length); - if (usedLength) { - *usedLength = length; - } - if (remainingRange) { - remainingRange->location = range.location + length; - remainingRange->length = range.length - length; - } - OSSpinLockUnlock(&lock_); - if (length > 0) { - return YES; - } else { - return NO; - } - } else { - GPBStringInitStringValueAlreadyLocked(self); - OSSpinLockUnlock(&lock_); - } - } else { - GPBStringInitStringValue(self); - } - return [(NSString *)string_ getBytes:buffer - maxLength:maxLength - usedLength:usedLength - encoding:encoding - options:options - range:range - remainingRange:remainingRange]; -} - -@end diff --git a/objectivec/GPBCodedInputStream_PackagePrivate.h b/objectivec/GPBCodedInputStream_PackagePrivate.h index e482b4c9..90bd0c92 100644 --- a/objectivec/GPBCodedInputStream_PackagePrivate.h +++ b/objectivec/GPBCodedInputStream_PackagePrivate.h @@ -39,19 +39,6 @@ @class GPBUnknownFieldSet; @class GPBFieldDescriptor; -// GPBString is a string subclass that avoids the overhead of initializing -// a full NSString until it is actually needed. Lots of protocol buffers contain -// strings, and instantiating all of those strings and having them parsed to -// verify correctness when the message was being read was expensive, when many -// of the strings were never being used. -// -// Note for future-self. I tried implementing this using a NSProxy. -// Turned out the performance was horrible in client apps because folks -// like to use libraries like SBJSON that grab characters one at a time. -// The proxy overhead was a killer. -@interface GPBString : NSString -@end - typedef struct GPBCodedInputStreamState { const uint8_t *bytes; size_t bufferSize; @@ -92,10 +79,6 @@ typedef struct GPBCodedInputStreamState { CF_EXTERN_C_BEGIN -// Returns a GPBString with a +1 retain count. -GPBString *GPBCreateGPBStringWithUTF8(const void *bytes, NSUInteger length) - __attribute__((ns_returns_retained)); - int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state); double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state); diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index d9080c3f..208cfe4e 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -568,13 +568,13 @@ static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!array) { // Check again after getting the lock. - OSSpinLockLock(&self->readOnlyMutex_); + dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!array) { array = CreateArrayForField(field, self); GPBSetAutocreatedRetainedObjectIvarWithField(self, field, array); } - OSSpinLockUnlock(&self->readOnlyMutex_); + dispatch_semaphore_signal(self->readOnlySemaphore_); } return array; } @@ -598,13 +598,13 @@ static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!dict) { // Check again after getting the lock. - OSSpinLockLock(&self->readOnlyMutex_); + dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!dict) { dict = CreateMapForField(field, self); GPBSetAutocreatedRetainedObjectIvarWithField(self, field, dict); } - OSSpinLockUnlock(&self->readOnlyMutex_); + dispatch_semaphore_signal(self->readOnlySemaphore_); } return dict; } @@ -810,7 +810,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { messageStorage_ = (GPBMessage_StoragePtr)( ((uint8_t *)self) + class_getInstanceSize([self class])); - readOnlyMutex_ = OS_SPINLOCK_INIT; + readOnlySemaphore_ = dispatch_semaphore_create(1); } return self; @@ -1723,7 +1723,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { } // Check for an autocreated value. - OSSpinLockLock(&readOnlyMutex_); + dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER); value = [autocreatedExtensionMap_ objectForKey:extension]; if (!value) { // Auto create the message extensions to match normal fields. @@ -1740,7 +1740,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { [value release]; } - OSSpinLockUnlock(&readOnlyMutex_); + dispatch_semaphore_signal(readOnlySemaphore_); return value; } diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h index d4c3501a..b7e24fc9 100644 --- a/objectivec/GPBMessage_PackagePrivate.h +++ b/objectivec/GPBMessage_PackagePrivate.h @@ -62,7 +62,12 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; // by *read* operations such as getters (autocreation of message fields and // message extensions, not setting of values). Used to guarantee thread safety // for concurrent reads on the message. - OSSpinLock readOnlyMutex_; + // NOTE: OSSpinLock may seem like a good fit here but Apple engineers have + // pointed out that they are vulnerable to live locking on iOS in cases of + // priority inversion: + // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/ + // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html + dispatch_semaphore_t readOnlySemaphore_; } // Gets an extension value without autocreating the result if not found. (i.e. diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m index 7036723f..4570716f 100644 --- a/objectivec/GPBRootObject.m +++ b/objectivec/GPBRootObject.m @@ -31,7 +31,6 @@ #import "GPBRootObject_PackagePrivate.h" #import <objc/runtime.h> -#import <libkern/OSAtomic.h> #import <CoreFoundation/CoreFoundation.h> @@ -96,13 +95,19 @@ static CFHashCode GPBRootExtensionKeyHash(const void *value) { return jenkins_one_at_a_time_hash(key); } -static OSSpinLock gExtensionSingletonDictionaryLock_ = OS_SPINLOCK_INIT; +// NOTE: OSSpinLock may seem like a good fit here but Apple engineers have +// pointed out that they are vulnerable to live locking on iOS in cases of +// priority inversion: +// http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/ +// https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html +static dispatch_semaphore_t gExtensionSingletonDictionarySemaphore; static CFMutableDictionaryRef gExtensionSingletonDictionary = NULL; static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL; + (void)initialize { // Ensure the global is started up. if (!gExtensionSingletonDictionary) { + gExtensionSingletonDictionarySemaphore = dispatch_semaphore_create(1); CFDictionaryKeyCallBacks keyCallBacks = { // See description above for reason for using custom dictionary. 0, @@ -134,9 +139,10 @@ static GPBExtensionRegistry *gDefaultExtensionRegistry = NULL; + (void)globallyRegisterExtension:(GPBExtensionDescriptor *)field { const char *key = [field singletonNameC]; - OSSpinLockLock(&gExtensionSingletonDictionaryLock_); + dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore, + DISPATCH_TIME_FOREVER); CFDictionarySetValue(gExtensionSingletonDictionary, key, field); - OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_); + dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore); } static id ExtensionForName(id self, SEL _cmd) { @@ -166,14 +172,24 @@ static id ExtensionForName(id self, SEL _cmd) { key[classNameLen] = '_'; memcpy(&key[classNameLen + 1], selName, selNameLen); key[classNameLen + 1 + selNameLen] = '\0'; - OSSpinLockLock(&gExtensionSingletonDictionaryLock_); + + // NOTE: Even though this method is called from another C function, + // gExtensionSingletonDictionarySemaphore and gExtensionSingletonDictionary + // will always be initialized. This is because this call flow is just to + // lookup the Extension, meaning the code is calling an Extension class + // message on a Message or Root class. This guarantees that the class was + // initialized and Message classes ensure their Root was also initialized. + NSAssert(gExtensionSingletonDictionary, @"Startup order broken!"); + + dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore, + DISPATCH_TIME_FOREVER); id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key); if (extension) { // The method is getting wired in to the class, so no need to keep it in // the dictionary. CFDictionaryRemoveValue(gExtensionSingletonDictionary, key); } - OSSpinLockUnlock(&gExtensionSingletonDictionaryLock_); + dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore); return extension; } diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index 5ee61230..eaa28bbc 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -411,7 +411,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { return field.defaultValue.valueMessage; } - OSSpinLockLock(&self->readOnlyMutex_); + dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!result) { // For non repeated messages, create the object, set it and return it. @@ -420,7 +420,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { result = GPBCreateMessageWithAutocreator(field.msgClass, self, field); GPBSetAutocreatedRetainedObjectIvarWithField(self, field, result); } - OSSpinLockUnlock(&self->readOnlyMutex_); + dispatch_semaphore_signal(self->readOnlySemaphore_); return result; } diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj index 1c834bb2..6b34b9bf 100644 --- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -28,7 +28,6 @@ 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; }; 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; - 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; }; 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; }; 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; }; 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; }; @@ -158,7 +157,6 @@ 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBARCUnittestProtos.m; sourceTree = "<group>"; }; 8B96157214C8B06000A2AC0B /* GPBDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBDescriptor.h; sourceTree = "<group>"; }; 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDescriptor.m; sourceTree = "<group>"; }; - 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; }; 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; }; 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; }; @@ -419,7 +417,6 @@ F4487C7E1AAF62CD00531423 /* GPBMessageTests+Serialization.m */, F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */, F41C175C1833D3310064ED4D /* GPBPerfTests.m */, - 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */, 8B4248BA1A8C256A00BC1EC6 /* GPBSwiftTests.swift */, 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */, 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */, @@ -689,7 +686,6 @@ F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */, F4353D341AC06F10005A6198 /* GPBDictionaryTests+Bool.m in Sources */, F4487C831AAF6AB300531423 /* GPBMessageTests+Merge.m in Sources */, - 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */, 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */, F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */, F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj index 55013641..e9d3fc95 100644 --- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -36,7 +36,6 @@ 8B9A5EB41831993600A9D33B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB31831993600A9D33B /* AppDelegate.m */; }; 8B9A5EB61831993600A9D33B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B9A5EB51831993600A9D33B /* Images.xcassets */; }; 8B9A5EEC18330A0F00A9D33B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A5E9F1831913D00A9D33B /* UIKit.framework */; }; - 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */; }; 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; }; 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; }; 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; }; @@ -179,7 +178,6 @@ 8B9A5EAD1831993600A9D33B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; 8B9A5EB31831993600A9D33B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; 8B9A5EB51831993600A9D33B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; }; - 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBStringTests.m; sourceTree = "<group>"; }; 8BBD9DB016DD1DC8008E1EC1 /* unittest_lite.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_lite.proto; path = ../../src/google/protobuf/unittest_lite.proto; sourceTree = "<group>"; }; 8BBEA4A6147C727100C4ADB7 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = "<group>"; }; @@ -457,7 +455,6 @@ F4487C801AAF62FC00531423 /* GPBMessageTests+Serialization.m */, F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */, F41C175C1833D3310064ED4D /* GPBPerfTests.m */, - 8BA9364418DA5F4B0056FA2A /* GPBStringTests.m */, 8B4248B31A8BD96E00BC1EC6 /* GPBSwiftTests.swift */, 7461B6AB0F94FDF800A0C422 /* GPBTestUtilities.h */, 7461B6AC0F94FDF800A0C422 /* GPBTestUtilities.m */, @@ -785,7 +782,6 @@ F41C175D1833D3310064ED4D /* GPBPerfTests.m in Sources */, F4353D421AC06F31005A6198 /* GPBDictionaryTests+Bool.m in Sources */, F4487C851AAF6AC500531423 /* GPBMessageTests+Merge.m in Sources */, - 8BA9364518DA5F4C0056FA2A /* GPBStringTests.m in Sources */, 8BBEA4B6147C727D00C4ADB7 /* GPBUnknownFieldSetTest.m in Sources */, F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */, F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m index 7c3c006b..b0e39d2c 100644 --- a/objectivec/Tests/GPBCodedInputStreamTests.m +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -266,6 +266,9 @@ } // Verifies fix for b/10315336. +// Note: Now that there isn't a custom string class under the hood, this test +// isn't as critical, but it does cover bad input and if a custom class is added +// again, it will help validate that class' handing of bad utf8. - (void)testReadMalformedString { NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; GPBCodedOutputStream* output = @@ -276,7 +279,7 @@ [output writeRawVarint32:tag]; [output writeRawVarint32:5]; // Create an invalid utf-8 byte array. - uint8_t bytes[5] = {0xc2, 0xf2}; + uint8_t bytes[] = {0xc2, 0xf2, 0x0, 0x0, 0x0}; [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]]; [output flush]; @@ -286,6 +289,7 @@ TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input extensionRegistry:nil error:NULL]; + XCTAssertNotNil(message); // Make sure we can read string properties twice without crashing. XCTAssertEqual([message.defaultString length], (NSUInteger)0); XCTAssertEqualObjects(@"", message.defaultString); diff --git a/objectivec/Tests/GPBStringTests.m b/objectivec/Tests/GPBStringTests.m deleted file mode 100644 index 802afa7d..00000000 --- a/objectivec/Tests/GPBStringTests.m +++ /dev/null @@ -1,513 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 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. - -#import <XCTest/XCTest.h> - -#import "GPBCodedInputStream_PackagePrivate.h" -#import "GPBTestUtilities.h" - -@interface TestClass : NSObject -@property(nonatomic, retain) NSString *foo; -@end - -@implementation TestClass -@synthesize foo; -@end - -@interface GPBStringTests : XCTestCase { - NSMutableArray *nsStrings_; - NSMutableArray *gpbStrings_; -} - -@end - -@implementation GPBStringTests - -- (void)setUp { - [super setUp]; - const char *strings[] = { - "ascii string", - "non-ascii string \xc3\xa9", // e with acute accent - "\xe2\x99\xa1", // White Heart - "mix \xe2\x99\xa4 string", // White Spade - - // Decomposed forms from http://www.unicode.org/reports/tr15/ - // 1.2 Singletons - "\xe2\x84\xa8 = A\xcc\x8a = \xc3\x85", "\xe2\x84\xa6 = \xce\xa9", - - // 1.2 Canonical Composites - "A\xcc\x8a = \xc3\x85", - "o\xcc\x82 = \xc3\xb4", - - // 1.2 Multiple Combining Marks - "s\xcc\xa3\xcc\x87 = \xe1\xb9\xa9", - "\xe1\xb8\x8b\xcc\xa3 = d\xcc\xa3\xcc\x87 = \xe1\xb8\x8d \xcc\x87", - "q\xcc\x87\xcc\xa3 = q\xcc\xa3\xcc\x87", - - // BOM - "\xEF\xBB\xBF String with BOM", - "String with \xEF\xBB\xBF in middle", - "String with end bom \xEF\xBB\xBF", - "\xEF\xBB\xBF\xe2\x99\xa1", // BOM White Heart - "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM", - - // Supplementary Plane - "\xf0\x9d\x84\x9e", // MUSICAL SYMBOL G CLEF - - // Tags - "\xf3\xa0\x80\x81", // Language Tag - - // Variation Selectors - "\xf3\xa0\x84\x80", // VARIATION SELECTOR-17 - - // Specials - "\xef\xbb\xbf\xef\xbf\xbd\xef\xbf\xbf", - - // Left To Right/Right To Left - // http://unicode.org/reports/tr9/ - - // Hello! <RTL marker>!Merhaba<LTR marker> - "Hello! \xE2\x80\x8F!\xd9\x85\xd8\xb1\xd8\xad\xd8\xa8\xd8\xa7\xE2\x80\x8E", - - "\xE2\x80\x8E LTR At Start", - "LTR At End\xE2\x80\x8E", - "\xE2\x80\x8F RTL At Start", - "RTL At End\xE2\x80\x8F", - "\xE2\x80\x8E\xE2\x80\x8E Double LTR \xE2\x80\x8E\xE2\x80\x8E", - "\xE2\x80\x8F\xE2\x80\x8F Double RTL \xE2\x80\x8F\xE2\x80\x8F", - "\xE2\x80\x8F\xE2\x80\x8E LTR-RTL LTR-RTL \xE2\x80\x8E\xE2\x80\x8F", - }; - size_t stringsSize = GPBARRAYSIZE(strings); - size_t numberUnicodeStrings = 17375; - nsStrings_ = [[NSMutableArray alloc] - initWithCapacity:stringsSize + numberUnicodeStrings]; - gpbStrings_ = [[NSMutableArray alloc] - initWithCapacity:stringsSize + numberUnicodeStrings]; - for (size_t i = 0; i < stringsSize; ++i) { - size_t length = strlen(strings[i]); - NSString *nsString = [[NSString alloc] initWithBytes:strings[i] - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - GPBString *gpbString = GPBCreateGPBStringWithUTF8(strings[i], length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - - // Generate all UTF8 characters in a variety of strings - // UTF8-1 - 1 Byte UTF 8 chars - int length = 0x7F + 1; - char *buffer = (char *)calloc(length, 1); - for (int i = 0; i < length; ++i) { - buffer[i] = (char)i; - } - NSString *nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - GPBString *gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - - // UTF8-2 - 2 Byte UTF 8 chars - int pointLength = 0xbf - 0x80 + 1; - length = pointLength * 2; - buffer = (char *)calloc(length, 1); - for (int i = 0xc2; i <= 0xdf; ++i) { - char *bufferPtr = buffer; - for (int j = 0x80; j <= 0xbf; ++j) { - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - free(buffer); - - // UTF8-3 - 3 Byte UTF 8 chars - length = pointLength * 3; - buffer = (char *)calloc(length, 1); - for (int i = 0xa0; i <= 0xbf; ++i) { - char *bufferPtr = buffer; - for (int j = 0x80; j <= 0xbf; ++j) { - (*bufferPtr++) = (char)0xE0; - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - for (int i = 0xe1; i <= 0xec; ++i) { - for (int j = 0x80; j <= 0xbf; ++j) { - char *bufferPtr = buffer; - for (int k = 0x80; k <= 0xbf; ++k) { - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - (*bufferPtr++) = (char)k; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - } - for (int i = 0x80; i <= 0x9f; ++i) { - char *bufferPtr = buffer; - for (int j = 0x80; j <= 0xbf; ++j) { - (*bufferPtr++) = (char)0xED; - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - for (int i = 0xee; i <= 0xef; ++i) { - for (int j = 0x80; j <= 0xbf; ++j) { - char *bufferPtr = buffer; - for (int k = 0x80; k <= 0xbf; ++k) { - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - (*bufferPtr++) = (char)k; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - } - free(buffer); - - // UTF8-4 - 4 Byte UTF 8 chars - length = pointLength * 4; - buffer = (char *)calloc(length, 1); - for (int i = 0x90; i <= 0xbf; ++i) { - for (int j = 0x80; j <= 0xbf; ++j) { - char *bufferPtr = buffer; - for (int k = 0x80; k <= 0xbf; ++k) { - (*bufferPtr++) = (char)0xF0; - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - (*bufferPtr++) = (char)k; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - } - for (int i = 0xf1; i <= 0xf3; ++i) { - for (int j = 0x80; j <= 0xbf; ++j) { - for (int k = 0x80; k <= 0xbf; ++k) { - char *bufferPtr = buffer; - for (int m = 0x80; m <= 0xbf; ++m) { - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - (*bufferPtr++) = (char)k; - (*bufferPtr++) = (char)m; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - } - } - for (int i = 0x80; i <= 0x8f; ++i) { - for (int j = 0x80; j <= 0xbf; ++j) { - char *bufferPtr = buffer; - for (int k = 0x80; k <= 0xbf; ++k) { - (*bufferPtr++) = (char)0xF4; - (*bufferPtr++) = (char)i; - (*bufferPtr++) = (char)j; - (*bufferPtr++) = (char)k; - } - nsString = [[NSString alloc] initWithBytes:buffer - length:length - encoding:NSUTF8StringEncoding]; - [nsStrings_ addObject:nsString]; - [nsString release]; - gpbString = GPBCreateGPBStringWithUTF8(buffer, length); - [gpbStrings_ addObject:gpbString]; - [gpbString release]; - } - } - free(buffer); -} - -- (void)tearDown { - [nsStrings_ release]; - [gpbStrings_ release]; - [super tearDown]; -} - -- (void)testLength { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - XCTAssertEqual([nsString length], [gpbString length], @"%@ %@", nsString, - gpbString); - ++i; - } -} - -- (void)testLengthOfBytesUsingEncoding { - NSStringEncoding encodings[] = { - NSUTF8StringEncoding, - NSASCIIStringEncoding, - NSISOLatin1StringEncoding, - NSMacOSRomanStringEncoding, - NSUTF16StringEncoding, - NSUTF32StringEncoding, - }; - - for (size_t j = 0; j < GPBARRAYSIZE(encodings); ++j) { - NSStringEncoding testEncoding = encodings[j]; - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - XCTAssertEqual([nsString lengthOfBytesUsingEncoding:testEncoding], - [gpbString lengthOfBytesUsingEncoding:testEncoding], - @"%@ %@", nsString, gpbString); - ++i; - } - } -} - -- (void)testHash { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - XCTAssertEqual([nsString hash], [gpbString hash], @"%@ %@", nsString, - gpbString); - ++i; - } -} - -- (void)testEquality { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - XCTAssertEqualObjects(nsString, gpbString); - ++i; - } -} - -- (void)testCharacterAtIndex { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - NSUInteger length = [nsString length]; - for (size_t j = 0; j < length; ++j) { - unichar nsChar = [nsString characterAtIndex:j]; - unichar pbChar = [gpbString characterAtIndex:j]; - XCTAssertEqual(nsChar, pbChar, @"%@ %@ %zu", nsString, gpbString, j); - } - ++i; - } -} - -- (void)testCopy { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = [[gpbStrings_[i] copy] autorelease]; - XCTAssertEqualObjects(nsString, gpbString); - ++i; - } -} - -- (void)testMutableCopy { - size_t i = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = [[gpbStrings_[i] mutableCopy] autorelease]; - XCTAssertEqualObjects(nsString, gpbString); - ++i; - } -} - -- (void)testGetBytes { - // Do an attempt at a reasonably exhaustive test of get bytes. - // Get bytes with options other than 0 should always fall through to Apple - // code so we don't bother testing that path. - size_t i = 0; - char pbBuffer[256]; - char nsBuffer[256]; - int count = 0; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i]; - for (int j = 0; j < 100; ++j) { - // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] - // does not return reliable results if the maxLength argument is 0, - // or range is 0,0. - // Radar 16385183 - NSUInteger length = [nsString length]; - NSUInteger maxBufferCount = (arc4random() % (length + 3)) + 1; - NSUInteger rangeStart = arc4random() % length; - NSUInteger rangeLength = arc4random() % (length - rangeStart); - - NSRange range = NSMakeRange(rangeStart, rangeLength); - - NSStringEncoding encodings[] = { - NSASCIIStringEncoding, - NSUTF8StringEncoding, - NSUTF16StringEncoding, - }; - - for (size_t k = 0; k < GPBARRAYSIZE(encodings); ++k) { - NSStringEncoding encoding = encodings[k]; - NSUInteger pbUsedBufferCount = 0; - NSUInteger nsUsedBufferCount = 0; - NSRange pbLeftOver = NSMakeRange(0, 0); - NSRange nsLeftOver = NSMakeRange(0, 0); - - BOOL pbGotBytes = [gpbString getBytes:pbBuffer - maxLength:maxBufferCount - usedLength:&pbUsedBufferCount - encoding:encoding - options:0 - range:range - remainingRange:&pbLeftOver]; - BOOL nsGotBytes = [nsString getBytes:nsBuffer - maxLength:maxBufferCount - usedLength:&nsUsedBufferCount - encoding:encoding - options:0 - range:range - remainingRange:&nsLeftOver]; - XCTAssertEqual( - (bool)pbGotBytes, (bool)nsGotBytes, - @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " - @"Used: %tu, %tu LeftOver %@, %@)", - count, gpbString, nsString, encoding, maxBufferCount, - NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, - NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); - XCTAssertEqual( - pbUsedBufferCount, nsUsedBufferCount, - @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " - @"Used: %tu, %tu LeftOver %@, %@)", - count, gpbString, nsString, encoding, maxBufferCount, - NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, - NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); - XCTAssertEqual( - pbLeftOver.location, nsLeftOver.location, - @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " - @"Used: %tu, %tu LeftOver %@, %@)", - count, gpbString, nsString, encoding, maxBufferCount, - NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, - NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); - XCTAssertEqual( - pbLeftOver.length, nsLeftOver.length, - @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " - @"Used: %tu, %tu LeftOver %@, %@)", - count, gpbString, nsString, encoding, maxBufferCount, - NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, - NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); - ++count; - } - } - ++i; - } -} - -- (void)testLengthAndGetBytes { - // This test exists as an attempt to ferret out a bug. - // http://b/13516532 - size_t i = 0; - char pbBuffer[256]; - char nsBuffer[256]; - for (NSString *nsString in nsStrings_) { - GPBString *gpbString = gpbStrings_[i++]; - NSUInteger nsLength = - [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - NSUInteger pbLength = - [gpbString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - XCTAssertEqual(nsLength, pbLength, @"%@ %@", nsString, gpbString); - NSUInteger pbUsedBufferCount = 0; - NSUInteger nsUsedBufferCount = 0; - NSRange pbLeftOver = NSMakeRange(0, 0); - NSRange nsLeftOver = NSMakeRange(0, 0); - NSRange range = NSMakeRange(0, [gpbString length]); - BOOL pbGotBytes = [gpbString getBytes:pbBuffer - maxLength:sizeof(pbBuffer) - usedLength:&pbUsedBufferCount - encoding:NSUTF8StringEncoding - options:0 - range:range - remainingRange:&pbLeftOver]; - BOOL nsGotBytes = [nsString getBytes:nsBuffer - maxLength:sizeof(nsBuffer) - usedLength:&nsUsedBufferCount - encoding:NSUTF8StringEncoding - options:0 - range:range - remainingRange:&nsLeftOver]; - XCTAssertTrue(pbGotBytes, @"%@", gpbString); - XCTAssertTrue(nsGotBytes, @"%@", nsString); - XCTAssertEqual(pbUsedBufferCount, pbLength, @"%@", gpbString); - XCTAssertEqual(nsUsedBufferCount, nsLength, @"%@", nsString); - } -} - -@end diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 9c72043b..e0230a24 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -353,7 +353,7 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { printer->Print( "public override string ToString() {\n" - " return pb::JsonFormatter.Default.Format(this);\n" + " return pb::JsonFormatter.ToDiagnosticString(this);\n" "}\n\n"); } |