diff options
33 files changed, 995 insertions, 167 deletions
diff --git a/Makefile.am b/Makefile.am index 4ece5217..6aa7e800 100644 --- a/Makefile.am +++ b/Makefile.am @@ -186,6 +186,7 @@ csharp_EXTRA_DIST= \ csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs \ csharp/src/Google.Protobuf/WireFormat.cs \ csharp/src/Google.Protobuf/project.json \ + csharp/src/global.json \ csharp/src/packages/repositories.config java_EXTRA_DIST= \ @@ -525,6 +526,7 @@ objectivec_EXTRA_DIST= \ objectivec/Tests/GPBDictionaryTests+String.m \ objectivec/Tests/GPBDictionaryTests+UInt32.m \ objectivec/Tests/GPBDictionaryTests+UInt64.m \ + objectivec/Tests/GPBDictionaryTests.m \ objectivec/Tests/GPBDictionaryTests.pddm \ objectivec/Tests/GPBMessageTests+Merge.m \ objectivec/Tests/GPBMessageTests+Runtime.m \ @@ -852,6 +854,7 @@ js_EXTRA_DIST= \ js/test3.proto \ js/test4.proto \ js/test5.proto \ + js/test8.proto \ js/test_bootstrap.js \ js/testbinary.proto \ js/testempty.proto diff --git a/composer.json b/composer.json index 2833f0a2..2b04e079 100644 --- a/composer.json +++ b/composer.json @@ -13,11 +13,11 @@ }, "autoload": { "psr-4": { - "Google\\Protobuf\\Internal\\": "src/Google/Protobuf/Internal", - "GPBMetadata\\Google\\Protobuf\\Internal\\": "src/GPBMetadata/Google/Protobuf/Internal" + "Google\\Protobuf\\Internal\\": "php/src/Google/Protobuf/Internal", + "GPBMetadata\\Google\\Protobuf\\Internal\\": "php/src/GPBMetadata/Google/Protobuf/Internal" }, "files": [ - "src/Google/Protobuf/descriptor.php" + "php/src/Google/Protobuf/descriptor.php" ] } } diff --git a/configure.ac b/configure.ac index d1e913c6..10fbdbd2 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,7 @@ AC_ARG_WITH([protoc], # Checks for programs. AC_PROG_CC AC_PROG_CXX +AC_PROG_CXX_FOR_BUILD AC_LANG([C++]) ACX_USE_SYSTEM_EXTENSIONS m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc index dd266d15..1e5387a5 100644 --- a/conformance/conformance_test.cc +++ b/conformance/conformance_test.cc @@ -109,13 +109,18 @@ string cat(const string& a, const string& b, // The maximum number of bytes that it takes to encode a 64-bit varint. #define VARINT_MAX_LEN 10 -size_t vencode64(uint64_t val, char *buf) { +size_t vencode64(uint64_t val, int over_encoded_bytes, char *buf) { if (val == 0) { buf[0] = 0; return 1; } size_t i = 0; while (val) { uint8_t byte = val & 0x7fU; val >>= 7; - if (val) byte |= 0x80U; + if (val || over_encoded_bytes) byte |= 0x80U; + buf[i++] = byte; + } + while (over_encoded_bytes--) { + assert(i < 10); + uint8_t byte = over_encoded_bytes ? 0x80 : 0; buf[i++] = byte; } return i; @@ -123,7 +128,15 @@ size_t vencode64(uint64_t val, char *buf) { string varint(uint64_t x) { char buf[VARINT_MAX_LEN]; - size_t len = vencode64(x, buf); + size_t len = vencode64(x, 0, buf); + return string(buf, len); +} + +// Encodes a varint that is |extra| bytes longer than it needs to be, but still +// valid. +string longvarint(uint64_t x, int extra) { + char buf[VARINT_MAX_LEN]; + size_t len = vencode64(x, extra, buf); return string(buf, len); } @@ -744,13 +757,23 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, }); TestValidDataForType(FieldDescriptor::TYPE_INT32, { {varint(12345), "12345"}, + {longvarint(12345, 2), "12345"}, + {longvarint(12345, 7), "12345"}, {varint(kInt32Max), std::to_string(kInt32Max)}, {varint(kInt32Min), std::to_string(kInt32Min)}, + {varint(1LL << 33), std::to_string(static_cast<int32>(1LL << 33))}, + {varint((1LL << 33) - 1), + std::to_string(static_cast<int32>((1LL << 33) - 1))}, }); TestValidDataForType(FieldDescriptor::TYPE_UINT32, { {varint(12345), "12345"}, + {longvarint(12345, 2), "12345"}, + {longvarint(12345, 7), "12345"}, {varint(kUint32Max), std::to_string(kUint32Max)}, // UINT32_MAX - {varint(0), "0"} + {varint(0), "0"}, + {varint(1LL << 33), std::to_string(static_cast<uint32>(1LL << 33))}, + {varint((1LL << 33) - 1), + std::to_string(static_cast<uint32>((1LL << 33) - 1))}, }); TestValidDataForType(FieldDescriptor::TYPE_FIXED64, { {u64(12345), "12345"}, diff --git a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs index ff2444a3..21aeb310 100644 --- a/csharp/src/Google.Protobuf.Test/ByteStringTest.cs +++ b/csharp/src/Google.Protobuf.Test/ByteStringTest.cs @@ -33,6 +33,10 @@ using System;
using System.Text;
using NUnit.Framework;
+using System.IO;
+#if !DOTNET35
+using System.Threading.Tasks;
+#endif
namespace Google.Protobuf
{
@@ -169,6 +173,56 @@ namespace Google.Protobuf }
[Test]
+ public void FromStream_Seekable()
+ {
+ var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
+ // Consume the first byte, just to test that it's "from current position"
+ stream.ReadByte();
+ var actual = ByteString.FromStream(stream);
+ ByteString expected = ByteString.CopyFrom(2, 3, 4, 5);
+ Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
+ }
+
+ [Test]
+ public void FromStream_NotSeekable()
+ {
+ var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
+ // Consume the first byte, just to test that it's "from current position"
+ stream.ReadByte();
+ // Wrap the original stream in LimitedInputStream, which has CanSeek=false
+ var limitedStream = new LimitedInputStream(stream, 3);
+ var actual = ByteString.FromStream(limitedStream);
+ ByteString expected = ByteString.CopyFrom(2, 3, 4);
+ Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
+ }
+
+#if !DOTNET35
+ [Test]
+ public async Task FromStreamAsync_Seekable()
+ {
+ var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
+ // Consume the first byte, just to test that it's "from current position"
+ stream.ReadByte();
+ var actual = await ByteString.FromStreamAsync(stream);
+ ByteString expected = ByteString.CopyFrom(2, 3, 4, 5);
+ Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
+ }
+
+ [Test]
+ public async Task FromStreamAsync_NotSeekable()
+ {
+ var stream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
+ // Consume the first byte, just to test that it's "from current position"
+ stream.ReadByte();
+ // Wrap the original stream in LimitedInputStream, which has CanSeek=false
+ var limitedStream = new LimitedInputStream(stream, 3);
+ var actual = await ByteString.FromStreamAsync(limitedStream);
+ ByteString expected = ByteString.CopyFrom(2, 3, 4);
+ Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
+ }
+#endif
+
+ [Test]
public void GetHashCode_Regression()
{
// We used to have an awful hash algorithm where only the last four
@@ -179,6 +233,5 @@ namespace Google.Protobuf ByteString b2 = ByteString.CopyFrom(200, 1, 2, 3, 4);
Assert.AreNotEqual(b1.GetHashCode(), b2.GetHashCode());
}
-
}
}
\ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/project.json b/csharp/src/Google.Protobuf.Test/project.json index 3a73bf7a..9f739f90 100644 --- a/csharp/src/Google.Protobuf.Test/project.json +++ b/csharp/src/Google.Protobuf.Test/project.json @@ -27,6 +27,7 @@ "testRunner": "nunit", "frameworks": { + "net451": {}, "netcoreapp1.0": { "imports" : [ "dnxcore50", "netcoreapp1.0", "portable-net45+win8" ], "buildOptions": { diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs index 5c652cc3..9973d211 100644 --- a/csharp/src/Google.Protobuf/ByteString.cs +++ b/csharp/src/Google.Protobuf/ByteString.cs @@ -35,6 +35,10 @@ using System.Collections; using System.Collections.Generic;
using System.IO;
using System.Text;
+#if !DOTNET35
+using System.Threading;
+using System.Threading.Tasks;
+#endif
namespace Google.Protobuf
{
@@ -142,6 +146,55 @@ namespace Google.Protobuf }
/// <summary>
+ /// Constructs a <see cref="ByteString"/> from data in the given stream, synchronously.
+ /// </summary>
+ /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
+ /// at the start of the call.</remarks>
+ /// <param name="stream">The stream to copy into a ByteString.</param>
+ /// <returns>A ByteString with content read from the given stream.</returns>
+ public static ByteString FromStream(Stream stream)
+ {
+ ProtoPreconditions.CheckNotNull(stream, nameof(stream));
+ int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
+ var memoryStream = new MemoryStream(capacity);
+ stream.CopyTo(memoryStream);
+#if NETSTANDARD1_0
+ byte[] bytes = memoryStream.ToArray();
+#else
+ // Avoid an extra copy if we can.
+ byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
+#endif
+ return AttachBytes(bytes);
+ }
+
+#if !DOTNET35
+ /// <summary>
+ /// Constructs a <see cref="ByteString"/> from data in the given stream, asynchronously.
+ /// </summary>
+ /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
+ /// at the start of the call.</remarks>
+ /// <param name="stream">The stream to copy into a ByteString.</param>
+ /// <param name="cancellationToken">The cancellation token to use when reading from the stream, if any.</param>
+ /// <returns>A ByteString with content read from the given stream.</returns>
+ public async static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ ProtoPreconditions.CheckNotNull(stream, nameof(stream));
+ int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
+ var memoryStream = new MemoryStream(capacity);
+ // We have to specify the buffer size here, as there's no overload accepting the cancellation token
+ // alone. But it's documented to use 81920 by default if not specified.
+ await stream.CopyToAsync(memoryStream, 81920, cancellationToken);
+#if NETSTANDARD1_0
+ byte[] bytes = memoryStream.ToArray();
+#else
+ // Avoid an extra copy if we can.
+ byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
+#endif
+ return AttachBytes(bytes);
+ }
+#endif
+
+ /// <summary>
/// Constructs a <see cref="ByteString" /> from the given array. The contents
/// are copied, so further modifications to the array will not
/// be reflected in the returned ByteString.
diff --git a/csharp/src/global.json b/csharp/src/global.json new file mode 100644 index 00000000..9d5558b1 --- /dev/null +++ b/csharp/src/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "1.0.0-preview2-003131" + } +} diff --git a/docs/third_party.md b/docs/third_party.md index 0bbde914..160090ce 100644 --- a/docs/third_party.md +++ b/docs/third_party.md @@ -32,6 +32,7 @@ These are projects we know about implementing Protocol Buffers for other program * Delphi: http://sourceforge.net/projects/protobuf-delphi/ * Delphi: http://fundementals.sourceforge.net/dl.html * Elixir: https://github.com/jeremyong/exprotoc +* Elm: https://github.com/tiziano88/elm-protobuf * Erlang: http://github.com/ngerakines/erlang_protobuffs/tree/master * Erlang: http://piqi.org/ * Erlang: https://code.google.com/p/protoc-gen-erl/ diff --git a/js/message_test.js b/js/message_test.js index 082da944..6d7cdd21 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -39,6 +39,9 @@ goog.require('goog.userAgent'); // CommonJS-LoadFromFile: google-protobuf jspb goog.require('jspb.Message'); +// CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested +goog.require('proto.jspb.exttest.nested.TestOuterMessage'); + // CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta goog.require('proto.jspb.exttest.beta.floatingStrField'); @@ -588,6 +591,14 @@ describe('Message test suite', function() { assertNotUndefined(proto.jspb.exttest.beta.floatingStrField); }); + it('testNestedExtensions', function() { + var extendable = new proto.jspb.exttest.nested.TestNestedExtensionsMessage(); + var extension = new proto.jspb.exttest.nested.TestOuterMessage.NestedExtensionMessage(['s1']); + extendable.setExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension, extension); + assertObjectEquals(extension, + extendable.getExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension)); + }); + it('testToObject_extendedObject', function() { var extension1 = new proto.jspb.test.IsExtension(['ext1field']); var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2'], true]); diff --git a/src/google/protobuf/arena_nc.cc b/js/test8.proto index f2f08427..2ae80dab 100644 --- a/src/google/protobuf/arena_nc.cc +++ b/js/test8.proto @@ -28,18 +28,23 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Negative compilation test for arena usage. +syntax = "proto2"; -#include <google/protobuf/arena.h> -#include <google/protobuf/unittest.pb.h> +option java_package = "com.google.apps.jspb.proto"; +option java_multiple_files = true; -#ifdef TEST_ARENA_PRIVATE_CONSTRUCTOR +package jspb.exttest.nested; -namespace google { -void ArenaPrivateConstructor() { - google::protobuf::Arena arena; - protobuf_unittest::TestAllTypes message(&arena); +message TestNestedExtensionsMessage { + optional int32 intfield = 1; + extensions 100 to max; } -#endif -} // namespace google +message TestOuterMessage { + message NestedExtensionMessage { + optional string ext1 = 1; + } + extend TestNestedExtensionsMessage { + optional NestedExtensionMessage inner_extension = 100; + } +} diff --git a/m4/ax_prog_cc_for_build.m4 b/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 00000000..77fd346a --- /dev/null +++ b/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/m4/ax_prog_cxx_for_build.m4 b/m4/ax_prog_cxx_for_build.m4 new file mode 100644 index 00000000..8cc0f73c --- /dev/null +++ b/m4/ax_prog_cxx_for_build.m4 @@ -0,0 +1,110 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cxx_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CXX_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C++ compiler that generates native +# executables, that is a C++ compiler that surely is not a cross-compiler. +# This can be useful if you have to generate source code at compile-time +# like for example GCC does. +# +# The macro sets the CXX_FOR_BUILD and CXXCPP_FOR_BUILD macros to anything +# needed to compile or link (CXX_FOR_BUILD) and preprocess +# (CXXCPP_FOR_BUILD). The value of these variables can be overridden by +# the user by specifying a compiler with an environment variable (like you +# do for standard CXX). +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org> +# Copyright (c) 2012 Avionic Design GmbH +# +# Based on the AX_PROG_CC_FOR_BUILD macro by Paolo Bonzini. +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AU_ALIAS([AC_PROG_CXX_FOR_BUILD], [AX_PROG_CXX_FOR_BUILD]) +AC_DEFUN([AX_PROG_CXX_FOR_BUILD], [dnl +AC_REQUIRE([AX_PROG_CC_FOR_BUILD])dnl +AC_REQUIRE([AC_PROG_CXX])dnl +AC_REQUIRE([AC_PROG_CXXCPP])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CXXCPP], ac_cv_build_prog_CXXCPP)dnl +pushdef([ac_cv_prog_gxx], ac_cv_build_prog_gxx)dnl +pushdef([ac_cv_prog_cxx_works], ac_cv_build_prog_cxx_works)dnl +pushdef([ac_cv_prog_cxx_cross], ac_cv_build_prog_cxx_cross)dnl +pushdef([ac_cv_prog_cxx_g], ac_cv_build_prog_cxx_g)dnl +pushdef([CXX], CXX_FOR_BUILD)dnl +pushdef([CXXCPP], CXXCPP_FOR_BUILD)dnl +pushdef([CXXFLAGS], CXXFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([CXXCPPFLAGS], CXXCPPFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cxxcpp], ac_build_cxxcpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CXX +AC_PROG_CXXCPP + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cxxcpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([CXXCPPFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CXXFLAGS])dnl +popdef([CXXCPP])dnl +popdef([CXX])dnl +popdef([ac_cv_prog_cxx_g])dnl +popdef([ac_cv_prog_cxx_cross])dnl +popdef([ac_cv_prog_cxx_works])dnl +popdef([ac_cv_prog_gxx])dnl +popdef([ac_cv_prog_CXXCPP])dnl + +dnl Finally, set Makefile variables +dnl +AC_SUBST([CXXFLAGS_FOR_BUILD])dnl +AC_SUBST([CXXCPPFLAGS_FOR_BUILD])dnl +]) diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh index ef8fb740..ea9fd273 100755 --- a/objectivec/DevTools/full_mac_build.sh +++ b/objectivec/DevTools/full_mac_build.sh @@ -265,6 +265,14 @@ if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then -destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.1" # 64bit ) ;; + 8.2* ) + XCODEBUILD_TEST_BASE_IOS+=( + -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit + -destination "platform=iOS Simulator,name=iPhone 7,OS=10.2" # 64bit + -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit + -destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.2" # 64bit + ) + ;; * ) echo "Time to update the simulator targets for Xcode ${XCODE_VERSION}" exit 2 diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m index ae57747d..f401631d 100644 --- a/objectivec/GPBArray.m +++ b/objectivec/GPBArray.m @@ -2519,14 +2519,14 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { - (id)copyWithZone:(NSZone *)zone { if (_array == nil) { - _array = [[NSMutableArray alloc] init]; + return [[NSMutableArray allocWithZone:zone] init]; } return [_array copyWithZone:zone]; } - (id)mutableCopyWithZone:(NSZone *)zone { if (_array == nil) { - _array = [[NSMutableArray alloc] init]; + return [[NSMutableArray allocWithZone:zone] init]; } return [_array mutableCopyWithZone:zone]; } diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m index fd8bd1ce..1c67c680 100644 --- a/objectivec/GPBDictionary.m +++ b/objectivec/GPBDictionary.m @@ -13579,22 +13579,26 @@ void GPBDictionaryReadEntry(id mapDictionary, - (id)copyWithZone:(NSZone *)zone { if (_dictionary == nil) { - _dictionary = [[NSMutableDictionary alloc] init]; + return [[NSMutableDictionary allocWithZone:zone] init]; } return [_dictionary copyWithZone:zone]; } - (id)mutableCopyWithZone:(NSZone *)zone { if (_dictionary == nil) { - _dictionary = [[NSMutableDictionary alloc] init]; + return [[NSMutableDictionary allocWithZone:zone] init]; } return [_dictionary mutableCopyWithZone:zone]; } +// Not really needed, but subscripting is likely common enough it doesn't hurt +// to ensure it goes directly to the real NSMutableDictionary. - (id)objectForKeyedSubscript:(id)key { return [_dictionary objectForKeyedSubscript:key]; } +// Not really needed, but subscripting is likely common enough it doesn't hurt +// to ensure it goes directly to the real NSMutableDictionary. - (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key { if (_dictionary == nil) { _dictionary = [[NSMutableDictionary alloc] init]; diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 4a6f0612..9660f1ed 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -1023,9 +1023,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { if (arrayOrMap) { if (field.fieldType == GPBFieldTypeRepeated) { if (GPBFieldDataTypeIsObject(field)) { - GPBAutocreatedArray *autoArray = arrayOrMap; - if (autoArray->_autocreator == self) { - autoArray->_autocreator = nil; + if ([arrayOrMap isKindOfClass:[GPBAutocreatedArray class]]) { + GPBAutocreatedArray *autoArray = arrayOrMap; + if (autoArray->_autocreator == self) { + autoArray->_autocreator = nil; + } } } else { // Type doesn't matter, it is a GPB*Array. @@ -1037,9 +1039,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { } else { if ((field.mapKeyDataType == GPBDataTypeString) && GPBFieldDataTypeIsObject(field)) { - GPBAutocreatedDictionary *autoDict = arrayOrMap; - if (autoDict->_autocreator == self) { - autoDict->_autocreator = nil; + if ([arrayOrMap isKindOfClass:[GPBAutocreatedDictionary class]]) { + GPBAutocreatedDictionary *autoDict = arrayOrMap; + if (autoDict->_autocreator == self) { + autoDict->_autocreator = nil; + } } } else { // Type doesn't matter, it is a GPB*Dictionary. diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index d4538598..68aadb77 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -408,9 +408,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, if (field.fieldType == GPBFieldTypeRepeated) { // If the old array was autocreated by us, then clear it. if (GPBDataTypeIsObject(fieldType)) { - GPBAutocreatedArray *autoArray = oldValue; - if (autoArray->_autocreator == self) { - autoArray->_autocreator = nil; + if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) { + GPBAutocreatedArray *autoArray = oldValue; + if (autoArray->_autocreator == self) { + autoArray->_autocreator = nil; + } } } else { // Type doesn't matter, it is a GPB*Array. @@ -423,9 +425,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, // If the old map was autocreated by us, then clear it. if ((field.mapKeyDataType == GPBDataTypeString) && GPBDataTypeIsObject(fieldType)) { - GPBAutocreatedDictionary *autoDict = oldValue; - if (autoDict->_autocreator == self) { - autoDict->_autocreator = nil; + if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) { + GPBAutocreatedDictionary *autoDict = oldValue; + if (autoDict->_autocreator == self) { + autoDict->_autocreator = nil; + } } } else { // Type doesn't matter, it is a GPB*Dictionary. diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj index 7ce5d54f..919d0076 100644 --- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -57,6 +57,7 @@ F47476E51D21A524007C7B1A /* Duration.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */; }; F47476E61D21A524007C7B1A /* Timestamp.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */; }; F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */; }; + F4C4B9E41E1D976300D3B61D /* GPBDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */; }; F4E675971B21D0000054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675871B21D0000054530B /* Any.pbobjc.m */; }; F4E675991B21D0000054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675891B21D0000054530B /* Api.pbobjc.m */; }; F4E6759B1B21D0000054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758B1B21D0000054530B /* Empty.pbobjc.m */; }; @@ -187,6 +188,7 @@ F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; }; F4B6B8B61A9CD1DE00892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; }; F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; }; + F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionaryTests.m; sourceTree = "<group>"; }; F4CF31701B162ED800BD9B06 /* unittest_objc_startup.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc_startup.proto; sourceTree = "<group>"; }; F4E675861B21D0000054530B /* Any.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Any.pbobjc.h; path = google/protobuf/Any.pbobjc.h; sourceTree = "<group>"; }; F4E675871B21D0000054530B /* Any.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = google/protobuf/Any.pbobjc.m; sourceTree = "<group>"; }; @@ -393,6 +395,7 @@ 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */, 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */, F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */, + F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */, F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */, F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */, F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */, @@ -677,6 +680,7 @@ F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */, F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */, + F4C4B9E41E1D976300D3B61D /* GPBDictionaryTests.m in Sources */, 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */, 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj index 5f599719..64fc45c0 100644 --- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -65,6 +65,7 @@ F47476E91D21A537007C7B1A /* Duration.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */; }; F47476EA1D21A537007C7B1A /* Timestamp.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */; }; F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */; }; + F4C4B9E71E1D97BF00D3B61D /* GPBDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */; }; F4E675D01B21D1620054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B71B21D1440054530B /* Any.pbobjc.m */; }; F4E675D11B21D1620054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B91B21D1440054530B /* Api.pbobjc.m */; }; F4E675D21B21D1620054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BC1B21D1440054530B /* Empty.pbobjc.m */; }; @@ -209,6 +210,7 @@ F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; }; F4B6B8B31A9CD1C600892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; }; F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; }; + F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionaryTests.m; sourceTree = "<group>"; }; F4CF31711B162EF500BD9B06 /* unittest_objc_startup.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc_startup.proto; sourceTree = "<group>"; }; F4E675B61B21D1440054530B /* Any.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Any.pbobjc.h; path = google/protobuf/Any.pbobjc.h; sourceTree = "<group>"; }; F4E675B71B21D1440054530B /* Any.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = google/protobuf/Any.pbobjc.m; sourceTree = "<group>"; }; @@ -431,6 +433,7 @@ 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */, 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */, F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */, + F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */, F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */, F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */, F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */, @@ -773,6 +776,7 @@ F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */, F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */, 8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */, + F4C4B9E71E1D97BF00D3B61D /* GPBDictionaryTests.m in Sources */, 8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */, 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m index 0fb15e40..31f75501 100644 --- a/objectivec/Tests/GPBArrayTests.m +++ b/objectivec/Tests/GPBArrayTests.m @@ -32,6 +32,7 @@ #import <XCTest/XCTest.h> #import "GPBArray.h" +#import "GPBArray_PackagePrivate.h" #import "GPBTestUtilities.h" @@ -3436,3 +3437,175 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { } @end + +#pragma mark - GPBAutocreatedArray Tests + +// These are hand written tests to double check some behaviors of the +// GPBAutocreatedArray. + +// NOTE: GPBAutocreatedArray is private to the library, users of the library +// should never have to directly deal with this class. + +@interface GPBAutocreatedArrayTests : XCTestCase +@end + +@implementation GPBAutocreatedArrayTests + +- (void)testEquality { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + XCTAssertTrue([array isEqual:@[]]); + XCTAssertTrue([array isEqualToArray:@[]]); + + XCTAssertFalse([array isEqual:@[ @"foo" ]]); + XCTAssertFalse([array isEqualToArray:@[ @"foo" ]]); + + [array addObject:@"foo"]; + + XCTAssertFalse([array isEqual:@[]]); + XCTAssertFalse([array isEqualToArray:@[]]); + XCTAssertTrue([array isEqual:@[ @"foo" ]]); + XCTAssertTrue([array isEqualToArray:@[ @"foo" ]]); + XCTAssertFalse([array isEqual:@[ @"bar" ]]); + XCTAssertFalse([array isEqualToArray:@[ @"bar" ]]); + + GPBAutocreatedArray *array2 = [[GPBAutocreatedArray alloc] init]; + + XCTAssertFalse([array isEqual:array2]); + XCTAssertFalse([array isEqualToArray:array2]); + + [array2 addObject:@"bar"]; + XCTAssertFalse([array isEqual:array2]); + XCTAssertFalse([array isEqualToArray:array2]); + + [array2 replaceObjectAtIndex:0 withObject:@"foo"]; + XCTAssertTrue([array isEqual:array2]); + XCTAssertTrue([array isEqualToArray:array2]); + + [array2 release]; + [array release]; +} + +- (void)testCopy { + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + NSArray *cpy = [array copy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSArray *cpy2 = [array copy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + // Can't compare cpy and cpy2 because NSArray has a singleton empty + // array it uses, so the ptrs are the same. + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + NSMutableArray *cpy = [array mutableCopy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSMutableArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSMutableArray *cpy2 = [array mutableCopy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSMutableArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + [array addObject:@"foo"]; + [array addObject:@"bar"]; + + NSArray *cpy = [array copy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[0], @"foo"); + XCTAssertEqualObjects(cpy[1], @"bar"); + + NSArray *cpy2 = [array copy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[0], @"foo"); + XCTAssertEqualObjects(cpy2[1], @"bar"); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + [array addObject:@"foo"]; + [array addObject:@"bar"]; + + NSMutableArray *cpy = [array mutableCopy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[0], @"foo"); + XCTAssertEqualObjects(cpy[1], @"bar"); + + NSMutableArray *cpy2 = [array mutableCopy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[0], @"foo"); + XCTAssertEqualObjects(cpy2[1], @"bar"); + + [cpy2 release]; + [cpy release]; + [array release]; + } +} + +- (void)testIndexedSubscriptSupport { + // The base NSArray/NSMutableArray behaviors for *IndexedSubscript methods + // should still work via the methods that one has to override to make an + // NSMutableArray subclass. i.e. - this should "just work" and if these + // crash/fail, then something is wrong in how NSMutableArray is subclassed. + + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + [array addObject:@"foo"]; + [array addObject:@"bar"]; + XCTAssertEqual(array.count, (NSUInteger)2); + XCTAssertEqualObjects(array[0], @"foo"); + XCTAssertEqualObjects(array[1], @"bar"); + array[0] = @"foo2"; + array[2] = @"baz"; + XCTAssertEqual(array.count, (NSUInteger)3); + XCTAssertEqualObjects(array[0], @"foo2"); + XCTAssertEqualObjects(array[1], @"bar"); + XCTAssertEqualObjects(array[2], @"baz"); + + [array release]; +} + +@end diff --git a/objectivec/Tests/GPBDictionaryTests.m b/objectivec/Tests/GPBDictionaryTests.m new file mode 100644 index 00000000..52b4b328 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests.m @@ -0,0 +1,186 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2017 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 <Foundation/Foundation.h> +#import <XCTest/XCTest.h> + +#import "GPBDictionary.h" +#import "GPBDictionary_PackagePrivate.h" + +#import "GPBTestUtilities.h" + +#pragma mark - GPBAutocreatedDictionary Tests + +// These are hand written tests to double check some behaviors of the +// GPBAutocreatedDictionary. The GPBDictionary+[type]Tests files are generate +// tests. + +// NOTE: GPBAutocreatedDictionary is private to the library, users of the +// library should never have to directly deal with this class. + +@interface GPBAutocreatedDictionaryTests : XCTestCase +@end + +@implementation GPBAutocreatedDictionaryTests + +- (void)testEquality { + GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init]; + + XCTAssertTrue([dict isEqual:@{}]); + XCTAssertTrue([dict isEqualToDictionary:@{}]); + + XCTAssertFalse([dict isEqual:@{ @"foo" : @"bar" }]); + XCTAssertFalse([dict isEqualToDictionary:@{ @"foo" : @"bar" }]); + + [dict setObject:@"bar" forKey:@"foo"]; + + XCTAssertFalse([dict isEqual:@{}]); + XCTAssertFalse([dict isEqualToDictionary:@{}]); + XCTAssertTrue([dict isEqual:@{ @"foo" : @"bar" }]); + XCTAssertTrue([dict isEqualToDictionary:@{ @"foo" : @"bar" }]); + XCTAssertFalse([dict isEqual:@{ @"bar" : @"baz" }]); + XCTAssertFalse([dict isEqualToDictionary:@{ @"bar" : @"baz" }]); + + GPBAutocreatedDictionary *dict2 = [[GPBAutocreatedDictionary alloc] init]; + + XCTAssertFalse([dict isEqual:dict2]); + XCTAssertFalse([dict isEqualToDictionary:dict2]); + + [dict2 setObject:@"mumble" forKey:@"foo"]; + XCTAssertFalse([dict isEqual:dict2]); + XCTAssertFalse([dict isEqualToDictionary:dict2]); + + [dict2 setObject:@"bar" forKey:@"foo"]; + XCTAssertTrue([dict isEqual:dict2]); + XCTAssertTrue([dict isEqualToDictionary:dict2]); + + [dict2 release]; + [dict release]; +} + +- (void)testCopy { + { + GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init]; + + NSDictionary *cpy = [dict copy]; + XCTAssertTrue(cpy != dict); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSDictionary class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSDictionary *cpy2 = [dict copy]; + XCTAssertTrue(cpy2 != dict); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSDictionary class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [dict release]; + } + + { + GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init]; + + NSMutableDictionary *cpy = [dict mutableCopy]; + XCTAssertTrue(cpy != dict); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSMutableDictionary class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSMutableDictionary *cpy2 = [dict mutableCopy]; + XCTAssertTrue(cpy2 != dict); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSMutableDictionary class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [dict release]; + } + + { + GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init]; + dict[@"foo"] = @"bar"; + dict[@"baz"] = @"mumble"; + + NSDictionary *cpy = [dict copy]; + XCTAssertTrue(cpy != dict); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSDictionary class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[@"foo"], @"bar"); + XCTAssertEqualObjects(cpy[@"baz"], @"mumble"); + + NSDictionary *cpy2 = [dict copy]; + XCTAssertTrue(cpy2 != dict); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSDictionary class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[@"foo"], @"bar"); + XCTAssertEqualObjects(cpy2[@"baz"], @"mumble"); + + [cpy2 release]; + [cpy release]; + [dict release]; + } + + { + GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init]; + dict[@"foo"] = @"bar"; + dict[@"baz"] = @"mumble"; + + NSMutableDictionary *cpy = [dict mutableCopy]; + XCTAssertTrue(cpy != dict); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSMutableDictionary class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[@"foo"], @"bar"); + XCTAssertEqualObjects(cpy[@"baz"], @"mumble"); + + NSMutableDictionary *cpy2 = [dict mutableCopy]; + XCTAssertTrue(cpy2 != dict); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSMutableDictionary class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[@"foo"], @"bar"); + XCTAssertEqualObjects(cpy2[@"baz"], @"mumble"); + + [cpy2 release]; + [cpy release]; + [dict release]; + } +} + +@end diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m index a3c5a6b4..c15535c5 100644 --- a/objectivec/Tests/GPBMessageTests.m +++ b/objectivec/Tests/GPBMessageTests.m @@ -1082,6 +1082,20 @@ [repeatedStringArray release]; } +- (void)testSetOverAutocreatedArrayAndSetAgain { + // Ensure when dealing with replacing an array it is handled being either + // an autocreated one or a straight NSArray. + + // The real test here is that nothing crashes while doing the work. + TestAllTypes *message = [TestAllTypes message]; + [message.repeatedStringArray addObject:@"foo"]; + XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)1); + message.repeatedStringArray = [NSMutableArray arrayWithObjects:@"bar", @"bar2", nil]; + XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)2); + message.repeatedStringArray = [NSMutableArray arrayWithObject:@"baz"]; + XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)1); +} + - (void)testReplaceAutocreatedArray { // Replacing array should orphan the old one and cause its creator to become // visible. @@ -1281,6 +1295,23 @@ [strToStr release]; } +- (void)testSetOverAutocreatedMapAndSetAgain { + // Ensure when dealing with replacing a map it is handled being either + // an autocreated one or a straight NSDictionary. + + // The real test here is that nothing crashes while doing the work. + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + message.strToStr[@"foo"] = @"bar"; + XCTAssertEqual(message.strToStr_Count, (NSUInteger)1); + message.strToStr = + [NSMutableDictionary dictionaryWithObjectsAndKeys:@"bar", @"key1", @"baz", @"key2", nil]; + XCTAssertEqual(message.strToStr_Count, (NSUInteger)2); + message.strToStr = + [NSMutableDictionary dictionaryWithObject:@"baz" forKey:@"mumble"]; + XCTAssertEqual(message.strToStr_Count, (NSUInteger)1); +} + - (void)testReplaceAutocreatedMap { // Replacing map should orphan the old one and cause its creator to become // visible. diff --git a/php/src/Google/Protobuf/Internal/InputStream.php b/php/src/Google/Protobuf/Internal/InputStream.php index 6d6c74e9..c5a76d5d 100644 --- a/php/src/Google/Protobuf/Internal/InputStream.php +++ b/php/src/Google/Protobuf/Internal/InputStream.php @@ -160,40 +160,59 @@ class InputStream */ public function readVarint64(&$var) { - $high = 0; - $low = 0; $count = 0; - $b = 0; - - do { - if ($this->current === $this->buffer_end) { - return false; - } - if ($count === self::MAX_VARINT_BYTES) { - return false; - } - $b = ord($this->buffer[$this->current]); - $bits = 7 * $count; - if ($bits >= 32) { - $high |= (($b & 0x7F) << ($bits - 32)); - } else if ($bits > 25){ - $high_bits = $bits - 25; - $low = ($low | (($b & 0x7F) << $bits)) & (int) 0xFFFFFFFF; - $high = $b & ((0x1 << $high_bits) -1); - } else { - $low |= (($b & 0x7F) << $bits); - } - - $this->advance(1); - $count += 1; - } while ($b & 0x80); if (PHP_INT_SIZE == 4) { + $high = 0; + $low = 0; + $b = 0; + + do { + if ($this->current === $this->buffer_end) { + return false; + } + if ($count === self::MAX_VARINT_BYTES) { + return false; + } + $b = ord($this->buffer[$this->current]); + $bits = 7 * $count; + if ($bits >= 32) { + $high |= (($b & 0x7F) << ($bits - 32)); + } else if ($bits > 25){ + $high_bits = $bits - 25; + $low = ($low | (($b & 0x7F) << $bits)) & (int) 0xFFFFFFFF; + $high = $b & ((0x1 << $high_bits) -1); + } else { + $low |= (($b & 0x7F) << $bits); + } + + $this->advance(1); + $count += 1; + } while ($b & 0x80); + $var = combineInt32ToInt64($high, $low); } else { - $var = ($high & 0xFFFFFFFF) << 32 | - ($low & 0xFFFFFFFF); + $result = 0; + $shift = 0; + + do { + if ($this->current === $this->buffer_end) { + return false; + } + if ($count === self::MAX_VARINT_BYTES) { + return false; + } + + $byte = ord($this->buffer[$this->current]); + $result |= ($byte & 0x7f) << $shift; + $shift += 7; + $this->advance(1); + $count += 1; + } while ($byte > 0x7f); + + $var = $result; } + return true; } diff --git a/php/tests/php_implementation_test.php b/php/tests/php_implementation_test.php index 4f626f1c..6b922a9b 100644 --- a/php/tests/php_implementation_test.php +++ b/php/tests/php_implementation_test.php @@ -366,6 +366,36 @@ class ImplementationTest extends TestBase $this->assertSame(32768, $var); } $this->assertFalse($input->readVarint64($var)); + + // Read 64 testing + if (PHP_INT_SIZE > 4) { + $testVals = array( + '10' => '0a000000000000000000', + '100' => '64000000000000000000', + '800' => 'a0060000000000000000', + '6400' => '80320000000000000000', + '70400' => '80a60400000000000000', + '774400' => '80a22f00000000000000', + '9292800' => '8098b704000000000000', + '74342400' => '80c0b923000000000000', + '743424000' => '8080bfe2020000000000', + '8177664000' => '8080b5bb1e0000000000', + '65421312000' => '8080a8dbf30100000000', + '785055744000' => '8080e0c7ec1600000000', + '9420668928000' => '808080dd969202000000', + '103627358208000' => '808080fff9c717000000', + '1139900940288000' => '808080f5bd9783020000', + '13678811283456000' => '808080fce699a6180000', + '109430490267648000' => '808080e0b7ceb1c20100', + '984874412408832000' => '808080e0f5c1bed50d00', + ); + + foreach ($testVals as $original => $encoded) { + $input = new InputStream(hex2bin($encoded)); + $this->assertTrue($input->readVarint64($var)); + $this->assertSame($original, $var); + } + } } public function testReadVarint32() diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py index c5f73dc1..ff3e6d30 100755 --- a/python/google/protobuf/internal/decoder.py +++ b/python/google/protobuf/internal/decoder.py @@ -131,9 +131,12 @@ def _VarintDecoder(mask, result_type): return DecodeVarint -def _SignedVarintDecoder(mask, result_type): +def _SignedVarintDecoder(bits, result_type): """Like _VarintDecoder() but decodes signed values.""" + signbit = 1 << (bits - 1) + mask = (1 << bits) - 1 + def DecodeVarint(buffer, pos): result = 0 shift = 0 @@ -142,11 +145,8 @@ def _SignedVarintDecoder(mask, result_type): result |= ((b & 0x7f) << shift) pos += 1 if not (b & 0x80): - if result > 0x7fffffffffffffff: - result -= (1 << 64) - result |= ~mask - else: - result &= mask + result &= mask + result = (result ^ signbit) - signbit result = result_type(result) return (result, pos) shift += 7 @@ -159,11 +159,11 @@ def _SignedVarintDecoder(mask, result_type): # (e.g. the C++ implementation) simpler. _DecodeVarint = _VarintDecoder((1 << 64) - 1, long) -_DecodeSignedVarint = _SignedVarintDecoder((1 << 64) - 1, long) +_DecodeSignedVarint = _SignedVarintDecoder(64, long) # Use these versions for values which must be limited to 32 bits. _DecodeVarint32 = _VarintDecoder((1 << 32) - 1, int) -_DecodeSignedVarint32 = _SignedVarintDecoder((1 << 32) - 1, int) +_DecodeSignedVarint32 = _SignedVarintDecoder(32, int) def ReadTag(buffer, pos): diff --git a/src/Makefile.am b/src/Makefile.am index 37204ea0..8807effd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,7 +57,8 @@ clean-local: CLEANFILES = $(protoc_outputs) unittest_proto_middleman \ testzip.jar testzip.list testzip.proto testzip.zip \ no_warning_test.cc \ - google/protobuf/compiler/js/well_known_types_embed.cc + google/protobuf/compiler/js/well_known_types_embed.cc \ + js_embed$(EXEEXT) MAINTAINERCLEANFILES = \ Makefile.in @@ -484,13 +485,16 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/csharp/csharp_wrapper_field.cc \ google/protobuf/compiler/csharp/csharp_wrapper_field.h -bin_PROGRAMS = protoc js_embed +bin_PROGRAMS = protoc protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la protoc_SOURCES = google/protobuf/compiler/main.cc # The special JS code for the well-known types is linked into the compiler via -# well_known_types_embed.cc, which is generated from .js source files. -js_embed_SOURCES = google/protobuf/compiler/js/embed.cc +# well_known_types_embed.cc, which is generated from .js source files. We have +# to build the js_embed binary using $(CXX_FOR_BUILD) so that it is executable +# on the build machine in a cross-compilation setup. +js_embed$(EXEEXT): $(srcdir)/google/protobuf/compiler/js/embed.cc + $(CXX_FOR_BUILD) -o $@ $< js_well_known_types_sources = \ google/protobuf/compiler/js/well_known_types/any.js \ google/protobuf/compiler/js/well_known_types/struct.js \ @@ -572,6 +576,7 @@ EXTRA_DIST = \ google/protobuf/package_info.h \ google/protobuf/io/package_info.h \ google/protobuf/util/package_info.h \ + google/protobuf/compiler/js/embed.cc \ google/protobuf/compiler/ruby/ruby_generated_code.proto \ google/protobuf/compiler/ruby/ruby_generated_code_pb.rb \ google/protobuf/compiler/package_info.h \ diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py deleted file mode 100644 index 56a7dd05..00000000 --- a/src/google/protobuf/arena_nc_test.py +++ /dev/null @@ -1,61 +0,0 @@ -#! /usr/bin/env python -# -# 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. - -"""Negative compilation unit tests for arena API.""" - -import unittest - -from google3.testing.pybase import fake_target_util -from google3.testing.pybase import unittest - - -class ArenaNcTest(unittest.TestCase): - - def testCompilerErrors(self): - """Runs a list of tests to verify compiler error messages.""" - - # Defines a list of test specs, where each element is a tuple - # (test name, list of regexes for matching the compiler errors). - test_specs = [ - ('ARENA_PRIVATE_CONSTRUCTOR', - [r'calling a protected constructor']), - ('SANITY', None)] - - fake_target_util.AssertCcCompilerErrors( - self, # The current test case. - 'google3/google/protobuf/arena_nc', # The fake target file. - 'arena_nc.o', # The sub-target to build. - test_specs # List of test specifications. - ) - -if __name__ == '__main__': - unittest.main() diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index d8fda59c..9cfd6ec6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -289,6 +289,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "classname", message_generators_[i]->classname_); } + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->index_in_metadata_ = i; + } + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->index_in_metadata_ = i; + } + if (HasGenericServices(file_, options_)) { + for (int i = 0; i < service_generators_.size(); i++) { + service_generators_[i]->index_in_metadata_ = i; + } + } + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" @@ -313,17 +325,8 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->index_in_metadata_ = i; message_generators_[i]->GenerateDescriptorDeclarations(printer); } - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->index_in_metadata_ = i; - } - if (HasGenericServices(file_, options_)) { - for (int i = 0; i < service_generators_.size(); i++) { - service_generators_[i]->index_in_metadata_ = i; - } - } printer->Print( "\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 2b71acb5..2d3d5640 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -1661,18 +1661,6 @@ void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) return; - // mutable_unknown_fields wrapper function for LazyStringOutputStream - // callback. - if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "static ::std::string* MutableUnknownFieldsFor$classname$(\n" - " $classname$* ptr) {\n" - " return ptr->mutable_unknown_fields();\n" - "}\n" - "\n", - "classname", classname_); - } if (IsAnyMessage(descriptor_)) { printer->Print( "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" @@ -2936,8 +2924,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // on the CodedOutputStream. printer->Print( " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " NewPermanentCallback(\n" - " &MutableUnknownFieldsFor$classname$, this));\n" + " ::google::protobuf::NewPermanentCallback(&_internal_metadata_,\n" + " &::google::protobuf::internal::InternalMetadataWithArenaLite::mutable_unknown_fields));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" " &unknown_fields_string, false);\n", "classname", classname_); diff --git a/src/google/protobuf/compiler/js/embed.cc b/src/google/protobuf/compiler/js/embed.cc index d04fea2e..57d38237 100644 --- a/src/google/protobuf/compiler/js/embed.cc +++ b/src/google/protobuf/compiler/js/embed.cc @@ -48,7 +48,7 @@ static char ToDecimalDigit(int num) { static std::string CEscape(const std::string& str) { std::string dest; - for (int i = 0; i < str.size(); ++i) { + for (size_t i = 0; i < str.size(); ++i) { unsigned char ch = str[i]; switch (ch) { case '\n': dest += "\\n"; break; @@ -98,7 +98,7 @@ static void AddFile(const char* name, std::basic_ostream<char>* out) { int main(int argc, char *argv[]) { std::cout << "#include " - "\"google/protobuf/compiler/js/well_known_types_embed.h\"\n"; + "<google/protobuf/compiler/js/well_known_types_embed.h>\n"; std::cout << "struct FileToc well_known_types_js[] = {\n"; for (int i = 1; i < argc; i++) { diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index e6571f6f..727ed090 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -1865,7 +1865,19 @@ void Generator::GenerateClass(const GeneratorOptions& options, // objects. GenerateClassDeserializeBinary(options, printer, desc); GenerateClassSerializeBinary(options, printer, desc); + } + + // Recurse on nested types. These must come *before* the extension-field + // info generation in GenerateClassRegistration so that extensions that + // reference nested types proceed the definitions of the nested types. + for (int i = 0; i < desc->enum_type_count(); i++) { + GenerateEnum(options, printer, desc->enum_type(i)); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + GenerateClass(options, printer, desc->nested_type(i)); + } + if (!NamespaceOnly(desc)) { GenerateClassRegistration(options, printer, desc); GenerateClassFields(options, printer, desc); if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") { @@ -1879,13 +1891,6 @@ void Generator::GenerateClass(const GeneratorOptions& options, } } - // Recurse on nested types. - for (int i = 0; i < desc->enum_type_count(); i++) { - GenerateEnum(options, printer, desc->enum_type(i)); - } - for (int i = 0; i < desc->nested_type_count(); i++) { - GenerateClass(options, printer, desc->nested_type(i)); - } } void Generator::GenerateClassConstructor(const GeneratorOptions& options, diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h index bbd507a8..9ec04979 100644 --- a/src/google/protobuf/stubs/callback.h +++ b/src/google/protobuf/stubs/callback.h @@ -346,6 +346,29 @@ struct InternalConstRef { typedef const base_type& type; }; +template<typename R, typename T> +class MethodResultCallback_0_0 : public ResultCallback<R> { + public: + typedef R (T::*MethodType)(); + MethodResultCallback_0_0(T* object, MethodType method, bool self_deleting) + : object_(object), + method_(method), + self_deleting_(self_deleting) {} + ~MethodResultCallback_0_0() {} + + R Run() { + bool needs_delete = self_deleting_; + R result = (object_->*method_)(); + if (needs_delete) delete this; + return result; + } + + private: + T* object_; + MethodType method_; + bool self_deleting_; +}; + template <typename R, typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename A1, typename A2> class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> { @@ -520,6 +543,13 @@ inline ResultCallback1<R, A1>* NewPermanentCallback( function, false, p1); } +// See MethodResultCallback_0_0 +template <typename R, typename T1, typename T2> +inline ResultCallback<R>* NewPermanentCallback( + T1* object, R (T2::*function)()) { + return new internal::MethodResultCallback_0_0<R, T1>(object, function, false); +} + // See MethodResultCallback_5_2 template <typename R, typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename A1, typename A2> |