aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD2
-rw-r--r--Makefile.am2
-rw-r--r--README.md2
-rw-r--r--csharp/README.md54
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf.Test/ByteStringTest.cs4
-rwxr-xr-xcsharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs67
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs2
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf.Test/FieldCodecTest.cs5
-rw-r--r--csharp/src/Google.Protobuf.Test/project.json4
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/ByteString.cs7
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/Collections/RepeatedField.cs2
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs4
-rwxr-xr-xcsharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs66
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs2
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/JsonFormatter.cs2
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs2
-rwxr-xr-x[-rw-r--r--]csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs2
-rw-r--r--objectivec/GPBUtilities.h5
-rw-r--r--objectivec/GPBUtilities.m119
-rw-r--r--objectivec/Tests/GPBUtilitiesTests.m200
-rw-r--r--src/google/protobuf/compiler/java/java_file.cc2
-rw-r--r--src/google/protobuf/generated_message_reflection.h2
-rw-r--r--src/google/protobuf/message.cc12
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.cc8
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.h9
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource_test.cc17
-rw-r--r--src/google/protobuf/util/json_util.cc30
-rw-r--r--src/google/protobuf/util/json_util.h11
-rw-r--r--src/google/protobuf/util/json_util_test.cc23
29 files changed, 626 insertions, 41 deletions
diff --git a/BUILD b/BUILD
index 3a1a1949..420fa337 100644
--- a/BUILD
+++ b/BUILD
@@ -27,7 +27,7 @@ config_setting(
# Android builds do not need to link in a separate pthread library.
LINK_OPTS = select({
":android": [],
- "//conditions:default": ["-lpthread"],
+ "//conditions:default": ["-lpthread", "-lm"],
})
load(
diff --git a/Makefile.am b/Makefile.am
index 1d1fb045..6b520b39 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -83,6 +83,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs \
csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs \
csharp/src/Google.Protobuf.Test/Compatibility/PropertyInfoExtensionsTest.cs \
+ csharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs \
csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs \
csharp/src/Google.Protobuf.Test/DeprecatedMemberTest.cs \
csharp/src/Google.Protobuf.Test/EqualityTester.cs \
@@ -125,6 +126,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs \
csharp/src/Google.Protobuf/Collections/RepeatedField.cs \
csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs \
+ csharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs \
csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs \
csharp/src/Google.Protobuf/FieldCodec.cs \
csharp/src/Google.Protobuf/FrameworkPortability.cs \
diff --git a/README.md b/README.md
index 2c1bce1a..b26e5424 100644
--- a/README.md
+++ b/README.md
@@ -74,4 +74,4 @@ Usage
The complete documentation for Protocol Buffers is available via the
web at:
- https://developers.google.com/protocol-buffers/
+https://developers.google.com/protocol-buffers/
diff --git a/csharp/README.md b/csharp/README.md
index ed5c7be7..65d2311f 100644
--- a/csharp/README.md
+++ b/csharp/README.md
@@ -32,8 +32,7 @@ Building
========
Open the `src/Google.Protobuf.sln` solution in Visual Studio 2015 or
-later. You should be able to run the NUnit test from Test Explorer
-(you might need to install NUnit Visual Studio add-in).
+later.
Although *users* of this project are only expected to have Visual
Studio 2012 or later, *developers* of the library are required to
@@ -42,6 +41,57 @@ in its implementation. These features have no impact when using the
compiled code - they're only relevant when building the
`Google.Protobuf` assembly.
+Testing
+=======
+
+The unit tests use [NUnit 3](https://github.com/nunit/nunit). Vanilla NUnit doesn't
+support .NET Core, so to run the tests you'll need to use
+[dotnet-test-nunit](https://github.com/nunit/dotnet-test-nunit).
+`dotnet-test-nunit` can also run tests for .NET 4.5+, so to run the tests
+for both .NET Core and .NET 4.5, you can simply open the
+`Package Manager Console` in Visual Studio and execute:
+```
+dotnet test Google.Protobuf.Test
+```
+
+.NET 3.5
+========
+
+We don't officially support .NET 3.5. However, there has been some effort
+to make enabling .NET 3.5 support relatively painless in case you require it.
+There's no guarantee that this will continue in the future, so rely on .NET
+3.5 support at your peril.
+
+To enable .NET 3.5 support:
+
+1. Modify [src/Google.Protobuf/project.json](src/Google.Protobuf/project.json) to add `"net35": {}` to `"frameworks"`.
+2. Modify [src/Google.Protobuf.Test/project.json](src/Google.Protobuf/project.json):
+ 1. Add `"net35": {}` to `"frameworks"`.
+ 2. `dotnet-test-nunit` doesn't support .NET 3.5, so remove it from
+ the project-wide `"dependencies"` and add it to the framework-specific
+ dependencies under `"net451"` and `"netcoreapp1.0"`.
+
+Note that `dotnet-test-nunit` doesn't support .NET 3.5. You can instead run the
+tests with [NUnit 3 console](https://github.com/nunit/nunit-console)
+by running something like:
+```
+nunit3-console.exe "Google.Protobuf.Test\bin\Debug\net35\win7-x64\Google.Protobuf.Test.dll" --inprocess
+```
+
+The exact path may differ depending on your environment (e.g., the `win7-x64`
+directory may be called something else). The `--inprocess` flag seems to be a
+necessary workaround for a bug in NUnit; otherwise, you'll receive
+an error "Exception has been thrown by the target of an invocation"
+([possibly related issue](https://github.com/nunit/nunit/issues/1480)).
+
+If you still want to run the .NET 4.5 and .NET Core tests, you can do so by
+specifying the framework when using `dotnet-test-nunit`, i.e. from
+`Package Manager Console` in Visual Studio:
+```
+dotnet test Google.Protobuf.Test --framework netcoreapp1.0
+dotnet test Google.Protobuf.Test --framework net451
+```
+
History of C# protobufs
=======================
diff --git a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs
index 21aeb310..afdd491f 100644..100755
--- a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs
+++ b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs
@@ -34,7 +34,7 @@ using System;
using System.Text;
using NUnit.Framework;
using System.IO;
-#if !DOTNET35
+#if !NET35
using System.Threading.Tasks;
#endif
@@ -196,7 +196,7 @@ namespace Google.Protobuf
Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
}
-#if !DOTNET35
+#if !NET35
[Test]
public async Task FromStreamAsync_Seekable()
{
diff --git a/csharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs b/csharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs
new file mode 100755
index 00000000..48c0725f
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs
@@ -0,0 +1,67 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if NET35
+using System;
+using System.IO;
+using NUnit.Framework;
+using Google.Protobuf.Compatibility;
+
+namespace Google.Protobuf.Test.Compatibility
+{
+ public class StreamExtensionsTest
+ {
+ [Test]
+ public void CopyToNullArgument()
+ {
+ var memoryStream = new MemoryStream();
+ Assert.Throws<ArgumentNullException>(() => memoryStream.CopyTo(null));
+ }
+
+ [Test]
+ public void CopyToTest()
+ {
+ byte[] bytesToStream = new byte[] { 0x31, 0x08, 0xFF, 0x00 };
+ Stream source = new MemoryStream(bytesToStream);
+ Stream destination = new MemoryStream((int)source.Length);
+ source.CopyTo(destination);
+ destination.Seek(0, SeekOrigin.Begin);
+
+ Assert.AreEqual(0x31, destination.ReadByte());
+ Assert.AreEqual(0x08, destination.ReadByte());
+ Assert.AreEqual(0xFF, destination.ReadByte());
+ Assert.AreEqual(0x00, destination.ReadByte());
+ Assert.AreEqual(-1, destination.ReadByte());
+ }
+ }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs
index f430b06b..abbe3c95 100644..100755
--- a/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Compatibility/TypeExtensionsTest.cs
@@ -34,7 +34,7 @@ using System;
using System.Collections.Generic;
using System.Reflection;
-#if !DOTNET35
+#if !NET35
namespace Google.Protobuf.Compatibility
{
public class TypeExtensionsTest
diff --git a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
index 0e2bad59..77641163 100644..100755
--- a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
+++ b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs
@@ -158,7 +158,9 @@ namespace Google.Protobuf
{
// WriteTagAndValue ignores default values
var stream = new MemoryStream();
- var codedOutput = new CodedOutputStream(stream);
+ CodedOutputStream codedOutput;
+#if !NET35
+ codedOutput = new CodedOutputStream(stream);
codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
codedOutput.Flush();
Assert.AreEqual(0, stream.Position);
@@ -167,6 +169,7 @@ namespace Google.Protobuf
{
Assert.AreEqual(default(T), codec.DefaultValue);
}
+#endif
// The plain ValueWriter/ValueReader delegates don't.
if (codec.DefaultValue != null) // This part isn't appropriate for message types.
diff --git a/csharp/src/Google.Protobuf.Test/project.json b/csharp/src/Google.Protobuf.Test/project.json
index 9f739f90..eaa7f79d 100644
--- a/csharp/src/Google.Protobuf.Test/project.json
+++ b/csharp/src/Google.Protobuf.Test/project.json
@@ -20,8 +20,8 @@
"dependencies": {
"Google.Protobuf": { "target": "project" },
- "NUnit": "3.4.0",
- "dotnet-test-nunit": "3.4.0-alpha-2"
+ "dotnet-test-nunit": "3.4.0-beta-3",
+ "NUnit": "3.6.0"
},
"testRunner": "nunit",
diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs
index 9973d211..4abdb718 100644..100755
--- a/csharp/src/Google.Protobuf/ByteString.cs
+++ b/csharp/src/Google.Protobuf/ByteString.cs
@@ -35,10 +35,13 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
-#if !DOTNET35
+#if !NET35
using System.Threading;
using System.Threading.Tasks;
#endif
+#if NET35
+using Google.Protobuf.Compatibility;
+#endif
namespace Google.Protobuf
{
@@ -167,7 +170,7 @@ namespace Google.Protobuf
return AttachBytes(bytes);
}
-#if !DOTNET35
+#if !NET35
/// <summary>
/// Constructs a <see cref="ByteString"/> from data in the given stream, asynchronously.
/// </summary>
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index 9504d7ef..6063ff61 100644..100755
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -47,7 +47,7 @@ namespace Google.Protobuf.Collections
/// </remarks>
/// <typeparam name="T">The element type of the repeated field.</typeparam>
public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
-#if !DOTNET35
+#if !NET35
, IReadOnlyList<T>
#endif
{
diff --git a/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
index e3914dd3..95a02c72 100644..100755
--- a/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
+++ b/csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs
@@ -47,7 +47,7 @@ namespace Google.Protobuf.Compatibility
/// </summary>
internal static MethodInfo GetGetMethod(this PropertyInfo target)
{
-#if DOTNET35
+#if NET35
var method = target.GetGetMethod();
#else
var method = target.GetMethod;
@@ -61,7 +61,7 @@ namespace Google.Protobuf.Compatibility
/// </summary>
internal static MethodInfo GetSetMethod(this PropertyInfo target)
{
-#if DOTNET35
+#if NET35
var method = target.GetSetMethod();
#else
var method = target.SetMethod;
diff --git a/csharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs
new file mode 100755
index 00000000..bf4bf220
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/StreamExtensions.cs
@@ -0,0 +1,66 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if NET35
+using System;
+using System.IO;
+
+namespace Google.Protobuf.Compatibility
+{
+ /// <summary>
+ /// Extension methods for <see cref="Stream"/> in order to provide
+ /// backwards compatibility with .NET 3.5
+ /// </summary>
+ public static class StreamExtensions
+ {
+ // 81920 seems to be the default buffer size used in .NET 4.5.1
+ private const int BUFFER_SIZE = 81920;
+
+ /// <summary>
+ /// Write the contents of the current stream to the destination stream
+ /// </summary>
+ public static void CopyTo(this Stream source, Stream destination)
+ {
+ if (destination == null)
+ {
+ throw new ArgumentNullException(nameof(destination));
+ }
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int numBytesRead;
+ while ((numBytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
+ destination.Write(buffer, 0, numBytesRead);
+ }
+ }
+ }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
index 2d93183b..2f237138 100644..100755
--- a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
+++ b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
@@ -33,7 +33,7 @@
using System;
using System.Reflection;
-#if !DOTNET35
+#if !NET35
namespace Google.Protobuf.Compatibility
{
/// <summary>
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index bb1a361e..05282775 100644..100755
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -831,7 +831,7 @@ namespace Google.Protobuf
return originalName;
}
-#if DOTNET35
+#if NET35
// TODO: Consider adding functionality to TypeExtensions to avoid this difference.
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
index 4a0922e8..86942acc 100644..100755
--- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -34,7 +34,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-#if DOTNET35
+#if NET35
// Needed for ReadOnlyDictionary, which does not exist in .NET 3.5
using Google.Protobuf.Collections;
#endif
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
index 0685c21a..4b0670f6 100644..100755
--- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -59,7 +59,7 @@ namespace Google.Protobuf.WellKnownTypes
if (firstInvalid == null)
{
var writer = new StringWriter();
-#if DOTNET35
+#if NET35
var query = paths.Select(JsonFormatter.ToJsonName);
JsonFormatter.WriteString(writer, string.Join(",", query.ToArray()));
#else
diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h
index 52e7d2e0..5464dfb3 100644
--- a/objectivec/GPBUtilities.h
+++ b/objectivec/GPBUtilities.h
@@ -392,6 +392,11 @@ void GPBSetMessageMapField(GPBMessage *self,
**/
NSData *GPBEmptyNSData(void) __attribute__((pure));
+/**
+ * Drops the `unknownFields` from the given message and from all sub message.
+ **/
+void GPBMessageDropUnknownFieldsRecursively(GPBMessage *message);
+
NS_ASSUME_NONNULL_END
CF_EXTERN_C_END
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 68aadb77..1843478c 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -58,6 +58,125 @@ NSData *GPBEmptyNSData(void) {
return defaultNSData;
}
+void GPBMessageDropUnknownFieldsRecursively(GPBMessage *initialMessage) {
+ if (!initialMessage) {
+ return;
+ }
+
+ // Use an array as a list to process to avoid recursion.
+ NSMutableArray *todo = [NSMutableArray arrayWithObject:initialMessage];
+
+ while (todo.count) {
+ GPBMessage *msg = todo.lastObject;
+ [todo removeLastObject];
+
+ // Clear unknowns.
+ msg.unknownFields = nil;
+
+ // Handle the message fields.
+ GPBDescriptor *descriptor = [[msg class] descriptor];
+ for (GPBFieldDescriptor *field in descriptor->fields_) {
+ if (!GPBFieldDataTypeIsMessage(field)) {
+ continue;
+ }
+ switch (field.fieldType) {
+ case GPBFieldTypeSingle:
+ if (GPBGetHasIvarField(msg, field)) {
+ GPBMessage *fieldMessage = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ [todo addObject:fieldMessage];
+ }
+ break;
+
+ case GPBFieldTypeRepeated: {
+ NSArray *fieldMessages = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ if (fieldMessages.count) {
+ [todo addObjectsFromArray:fieldMessages];
+ }
+ break;
+ }
+
+ case GPBFieldTypeMap: {
+ id rawFieldMap = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
+ switch (field.mapKeyDataType) {
+ case GPBDataTypeBool:
+ [(GPBBoolObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ BOOL key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeFixed32:
+ case GPBDataTypeUInt32:
+ [(GPBUInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ uint32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeInt32:
+ case GPBDataTypeSFixed32:
+ case GPBDataTypeSInt32:
+ [(GPBInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ int32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeFixed64:
+ case GPBDataTypeUInt64:
+ [(GPBUInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ uint64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeInt64:
+ case GPBDataTypeSFixed64:
+ case GPBDataTypeSInt64:
+ [(GPBInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ int64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:object];
+ }];
+ break;
+ case GPBDataTypeString:
+ [(NSDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
+ NSString * _Nonnull key, GPBMessage * _Nonnull obj, BOOL * _Nonnull stop) {
+ #pragma unused(key, stop)
+ [todo addObject:obj];
+ }];
+ break;
+ case GPBDataTypeFloat:
+ case GPBDataTypeDouble:
+ case GPBDataTypeEnum:
+ case GPBDataTypeBytes:
+ case GPBDataTypeGroup:
+ case GPBDataTypeMessage:
+ NSCAssert(NO, @"Aren't valid key types.");
+ }
+ break;
+ } // switch(field.mapKeyDataType)
+ } // switch(field.fieldType)
+ } // for(fields)
+
+ // Handle any extensions holding messages.
+ for (GPBExtensionDescriptor *extension in [msg extensionsCurrentlySet]) {
+ if (!GPBDataTypeIsMessage(extension.dataType)) {
+ continue;
+ }
+ if (extension.isRepeated) {
+ NSArray *extMessages = [msg getExtension:extension];
+ [todo addObjectsFromArray:extMessages];
+ } else {
+ GPBMessage *extMessage = [msg getExtension:extension];
+ [todo addObject:extMessage];
+ }
+ } // for(extensionsCurrentlySet)
+
+ } // while(todo.count)
+}
+
+
// -- About Version Checks --
// There's actually 3 places these checks all come into play:
// 1. When the generated source is compile into .o files, the header check
diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m
index dfaca660..2e206a54 100644
--- a/objectivec/Tests/GPBUtilitiesTests.m
+++ b/objectivec/Tests/GPBUtilitiesTests.m
@@ -39,6 +39,7 @@
#import "GPBDescriptor.h"
#import "GPBDescriptor_PackagePrivate.h"
#import "GPBMessage.h"
+#import "GPBUnknownField_PackagePrivate.h"
#import "google/protobuf/MapUnittest.pbobjc.h"
#import "google/protobuf/Unittest.pbobjc.h"
@@ -197,4 +198,203 @@
}
}
+// Helper to make an unknown field set with something in it.
+static GPBUnknownFieldSet *UnknownFieldsSetHelper(int num) {
+ GPBUnknownFieldSet *result =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+
+ GPBUnknownField *field =
+ [[[GPBUnknownField alloc] initWithNumber:num] autorelease];
+ [field addVarint:num];
+ [result addField:field];
+
+ return result;
+}
+
+- (void)testDropMessageUnknownFieldsRecursively {
+ TestAllExtensions *message = [TestAllExtensions message];
+
+ // Give it unknownFields.
+ message.unknownFields = UnknownFieldsSetHelper(777);
+
+ // Given it extensions that include a message with unknown fields of its own.
+ {
+ // Int
+ [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
+
+ // Group
+ OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message];
+ optionalGroup.a = 123;
+ optionalGroup.unknownFields = UnknownFieldsSetHelper(779);
+ [message setExtension:[UnittestRoot optionalGroupExtension]
+ value:optionalGroup];
+
+ // Message
+ TestAllTypes_NestedMessage *nestedMessage =
+ [TestAllTypes_NestedMessage message];
+ nestedMessage.bb = 456;
+ nestedMessage.unknownFields = UnknownFieldsSetHelper(778);
+ [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+ value:nestedMessage];
+
+ // Repeated Group
+ RepeatedGroup_extension *repeatedGroup =
+ [[RepeatedGroup_extension alloc] init];
+ repeatedGroup.a = 567;
+ repeatedGroup.unknownFields = UnknownFieldsSetHelper(780);
+ [message addExtension:[UnittestRoot repeatedGroupExtension]
+ value:repeatedGroup];
+ [repeatedGroup release];
+
+ // Repeated Message
+ nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
+ nestedMessage.bb = 678;
+ nestedMessage.unknownFields = UnknownFieldsSetHelper(781);
+ [message addExtension:[UnittestRoot repeatedNestedMessageExtension]
+ value:nestedMessage];
+ [nestedMessage release];
+ }
+
+ // Confirm everything is there.
+
+ XCTAssertNotNil(message);
+ XCTAssertNotNil(message.unknownFields);
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ OptionalGroup_extension *optionalGroup =
+ [message getExtension:[UnittestRoot optionalGroupExtension]];
+ XCTAssertNotNil(optionalGroup);
+ XCTAssertEqual(optionalGroup.a, 123);
+ XCTAssertNotNil(optionalGroup.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+ TestAllTypes_NestedMessage *nestedMessage =
+ [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
+ XCTAssertNotNil(nestedMessage);
+ XCTAssertEqual(nestedMessage.bb, 456);
+ XCTAssertNotNil(nestedMessage.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
+ NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
+ XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
+ RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
+ XCTAssertNotNil(repeatedGroup);
+ XCTAssertEqual(repeatedGroup.a, 567);
+ XCTAssertNotNil(repeatedGroup.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
+ NSArray *repeatedNestedMessages = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
+ XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
+ TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
+ XCTAssertNotNil(repeatedNestedMessage);
+ XCTAssertEqual(repeatedNestedMessage.bb, 678);
+ XCTAssertNotNil(repeatedNestedMessage.unknownFields);
+ }
+
+ // Drop them.
+ GPBMessageDropUnknownFieldsRecursively(message);
+
+ // Confirm unknowns are gone from within the messages.
+
+ XCTAssertNotNil(message);
+ XCTAssertNil(message.unknownFields);
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ OptionalGroup_extension *optionalGroup =
+ [message getExtension:[UnittestRoot optionalGroupExtension]];
+ XCTAssertNotNil(optionalGroup);
+ XCTAssertEqual(optionalGroup.a, 123);
+ XCTAssertNil(optionalGroup.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+ TestAllTypes_NestedMessage *nestedMessage =
+ [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
+ XCTAssertNotNil(nestedMessage);
+ XCTAssertEqual(nestedMessage.bb, 456);
+ XCTAssertNil(nestedMessage.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
+ NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
+ XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
+ RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
+ XCTAssertNotNil(repeatedGroup);
+ XCTAssertEqual(repeatedGroup.a, 567);
+ XCTAssertNil(repeatedGroup.unknownFields);
+ }
+
+ {
+ XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
+ NSArray *repeatedNestedMessages = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
+ XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
+ TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
+ XCTAssertNotNil(repeatedNestedMessage);
+ XCTAssertEqual(repeatedNestedMessage.bb, 678);
+ XCTAssertNil(repeatedNestedMessage.unknownFields);
+ }
+
+}
+
+- (void)testDropMessageUnknownFieldsRecursively_Maps {
+ TestMap *message = [TestMap message];
+
+ {
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ foreignMessage.unknownFields = UnknownFieldsSetHelper(100);
+ [message.mapInt32ForeignMessage setObject:foreignMessage forKey:100];
+
+ foreignMessage = [ForeignMessage message];
+ foreignMessage.unknownFields = UnknownFieldsSetHelper(101);
+ [message.mapStringForeignMessage setObject:foreignMessage forKey:@"101"];
+ }
+
+ // Confirm everything is there.
+
+ XCTAssertNotNil(message);
+
+ {
+ ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
+ XCTAssertNotNil(foreignMessage);
+ XCTAssertNotNil(foreignMessage.unknownFields);
+ }
+
+ {
+ ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
+ XCTAssertNotNil(foreignMessage);
+ XCTAssertNotNil(foreignMessage.unknownFields);
+ }
+
+ GPBMessageDropUnknownFieldsRecursively(message);
+
+ // Confirm unknowns are gone from within the messages.
+
+ XCTAssertNotNil(message);
+
+ {
+ ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
+ XCTAssertNotNil(foreignMessage);
+ XCTAssertNil(foreignMessage.unknownFields);
+ }
+
+ {
+ ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
+ XCTAssertNotNil(foreignMessage);
+ XCTAssertNil(foreignMessage.unknownFields);
+ }
+
+}
+
@end
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index cb4503f6..86719f70 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -65,7 +65,7 @@ namespace java {
namespace {
struct FieldDescriptorCompare {
- bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) {
+ bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) const {
if(f1 == NULL) {
return false;
}
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 2e65787f..8b1362a2 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -674,6 +674,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection PROTOBUF_FINAL
template<typename To, typename From>
inline To dynamic_cast_if_available(From from) {
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
+ // Avoid the compiler warning about unused variables.
+ (void)from;
return NULL;
#else
return dynamic_cast<To>(from);
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index b799dead..6800e4cd 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -451,8 +451,8 @@ struct ShutdownRepeatedFieldRegister {
namespace internal {
template<>
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
-// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240
GOOGLE_ATTRIBUTE_NOINLINE
#endif
Message* GenericTypeHandler<Message>::NewFromPrototype(
@@ -460,8 +460,8 @@ Message* GenericTypeHandler<Message>::NewFromPrototype(
return prototype->New(arena);
}
template<>
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
-// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240
GOOGLE_ATTRIBUTE_NOINLINE
#endif
google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
@@ -469,8 +469,8 @@ google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
return value->GetArena();
}
template<>
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
-// Note: force noinline to workaround MSVC 2015 compiler bug, issue #240
+#if defined(_MSC_VER) && (_MSC_VER >= 1800)
+// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240
GOOGLE_ATTRIBUTE_NOINLINE
#endif
void* GenericTypeHandler<Message>::GetMaybeArenaPointer(
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 3591febf..f9fd7b01 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -120,6 +120,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource(
own_typeinfo_(true),
type_(type),
use_lower_camel_for_enums_(false),
+ use_ints_for_enums_(false),
recursion_depth_(0),
max_recursion_depth_(kDefaultMaxRecursionDepth),
render_unknown_fields_(false),
@@ -135,6 +136,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource(
own_typeinfo_(false),
type_(type),
use_lower_camel_for_enums_(false),
+ use_ints_for_enums_(false),
recursion_depth_(0),
max_recursion_depth_(kDefaultMaxRecursionDepth),
render_unknown_fields_(false),
@@ -858,6 +860,12 @@ Status ProtoStreamObjectSource::RenderNonMessageField(
break;
}
+ // No need to lookup enum type if we need to render int.
+ if (use_ints_for_enums_) {
+ ow->RenderInt32(field_name, buffer32);
+ break;
+ }
+
// Get the nested enum type for this field.
// TODO(skarvaje): Avoid string manipulation. Find ways to speed this
// up.
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index 88ca652b..63d5f455 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -110,6 +110,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
use_lower_camel_for_enums_ = value;
}
+ // Sets whether to always output enums as ints, by default this is off, and
+ // enums are rendered as strings.
+ void set_use_ints_for_enums(bool value) {
+ use_ints_for_enums_ = value;
+ }
+
// Sets the max recursion depth of proto message to be deserialized. Proto
// messages over this depth will fail to be deserialized.
// Default value is 64.
@@ -285,6 +291,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
// Whether to render enums using lowerCamelCase. Defaults to false.
bool use_lower_camel_for_enums_;
+ // Whether to render enums as ints always. Defaults to false.
+ bool use_ints_for_enums_;
+
// Tracks current recursion depth.
mutable int recursion_depth_;
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
index 1286bdb9..e215c4ab 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -102,6 +102,7 @@ class ProtostreamObjectSourceTest
mock_(),
ow_(&mock_),
use_lower_camel_for_enums_(false),
+ use_ints_for_enums_(false),
add_trailing_zeros_(false) {
helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor());
}
@@ -123,6 +124,7 @@ class ProtostreamObjectSourceTest
google::protobuf::scoped_ptr<ProtoStreamObjectSource> os(
helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor)));
if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true);
+ if (use_ints_for_enums_) os->set_use_ints_for_enums(true);
os->set_max_recursion_depth(64);
return os->WriteTo(&mock_);
}
@@ -270,6 +272,8 @@ class ProtostreamObjectSourceTest
void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }
+ void UseIntsForEnums() { use_ints_for_enums_ = true; }
+
void AddTrailingZeros() { add_trailing_zeros_ = true; }
testing::TypeInfoTestHelper helper_;
@@ -277,6 +281,7 @@ class ProtostreamObjectSourceTest
::testing::NiceMock<MockObjectWriter> mock_;
ExpectingObjectWriter ow_;
bool use_lower_camel_for_enums_;
+ bool use_ints_for_enums_;
bool add_trailing_zeros_;
};
@@ -498,6 +503,18 @@ TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
DoTest(book, Book::descriptor());
}
+TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) {
+ Book book;
+ book.set_type(Book::ACTION_AND_ADVENTURE);
+
+ UseIntsForEnums();
+
+ ow_.StartObject("")
+ ->RenderInt32("type", 3)
+ ->EndObject();
+ DoTest(book, Book::descriptor());
+}
+
TEST_P(ProtostreamObjectSourceTest, UnknownEnum) {
Proto3Message message;
message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index d7ac2dba..129b6eaf 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -49,22 +49,25 @@ namespace protobuf {
namespace util {
namespace internal {
+ZeroCopyStreamByteSink::~ZeroCopyStreamByteSink() {
+ stream_->BackUp(buffer_size_);
+}
+
void ZeroCopyStreamByteSink::Append(const char* bytes, size_t len) {
- while (len > 0) {
- void* buffer;
- int length;
- if (!stream_->Next(&buffer, &length)) {
- // There isn't a way for ByteSink to report errors.
+ while (true) {
+ if (len <= buffer_size_) {
+ memcpy(buffer_, bytes, len);
+ buffer_ = static_cast<char*>(buffer_) + len;
+ buffer_size_ -= len;
return;
}
- if (len < length) {
- memcpy(buffer, bytes, len);
- stream_->BackUp(length - len);
- break;
- } else {
- memcpy(buffer, bytes, length);
- bytes += length;
- len -= length;
+ memcpy(buffer_, bytes, buffer_size_);
+ bytes += buffer_size_;
+ len -= buffer_size_;
+ if (!stream_->Next(&buffer_, &buffer_size_)) {
+ // There isn't a way for ByteSink to report errors.
+ buffer_size_ = 0;
+ return;
}
}
}
@@ -79,6 +82,7 @@ util::Status BinaryToJsonStream(TypeResolver* resolver,
google::protobuf::Type type;
RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type));
converter::ProtoStreamObjectSource proto_source(&in_stream, resolver, type);
+ proto_source.set_use_ints_for_enums(options.always_print_enums_as_ints);
io::CodedOutputStream out_stream(json_output);
converter::JsonObjectWriter json_writer(options.add_whitespace ? " " : "",
&out_stream);
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index 6d3cee52..53b1d1ba 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -61,9 +61,13 @@ struct JsonPrintOptions {
// set to 0 will be omitted. Set this flag to true will override the default
// behavior and print primitive fields regardless of their values.
bool always_print_primitive_fields;
+ // Whether to always print enums as ints. By default they are rendered as
+ // strings.
+ bool always_print_enums_as_ints;
JsonPrintOptions() : add_whitespace(false),
- always_print_primitive_fields(false) {
+ always_print_primitive_fields(false),
+ always_print_enums_as_ints(false) {
}
};
@@ -172,12 +176,15 @@ namespace internal {
class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
public:
explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
- : stream_(stream) {}
+ : stream_(stream), buffer_size_(0) {}
+ ~ZeroCopyStreamByteSink();
virtual void Append(const char* bytes, size_t len);
private:
io::ZeroCopyOutputStream* stream_;
+ void* buffer_;
+ int buffer_size_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
};
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index bf35ae3e..796718d5 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -160,6 +160,29 @@ TEST_F(JsonUtilTest, TestDefaultValues) {
ToJson(m, options));
}
+TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) {
+ TestMessage orig;
+ orig.set_enum_value(proto3::EnumType::BAR);
+ orig.add_repeated_enum_value(proto3::EnumType::FOO);
+ orig.add_repeated_enum_value(proto3::EnumType::BAR);
+
+ JsonPrintOptions print_options;
+ print_options.always_print_enums_as_ints = true;
+
+ string expected_json =
+ "{\"enumValue\":1,\"repeatedEnumValue\":[0,1]}";
+ EXPECT_EQ(expected_json, ToJson(orig, print_options));
+
+ TestMessage parsed;
+ JsonParseOptions parse_options;
+ ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
+
+ EXPECT_EQ(proto3::EnumType::BAR, parsed.enum_value());
+ EXPECT_EQ(2, parsed.repeated_enum_value_size());
+ EXPECT_EQ(proto3::EnumType::FOO, parsed.repeated_enum_value(0));
+ EXPECT_EQ(proto3::EnumType::BAR, parsed.repeated_enum_value(1));
+}
+
TEST_F(JsonUtilTest, ParseMessage) {
// Some random message but good enough to verify that the parsing warpper
// functions are working properly.